精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Key事件的分發邏輯,Android按鍵事件的產生與處理解析

移動開發 Android
KeyEvent類的dispatch方法實現了按鍵事件的分發和處理,為Android應用程序提供了豐富的按鍵事件處理能力。
  1. 「事件的產生」:當用戶按下物理按鍵、使用遙控器、輸入法或其他USB-OTG外接鍵盤等設備時,會產生按鍵事件(KeyEvent)。
  2. 「事件的分發」:
  • 「分發起點」:按鍵事件由Android系統接收,通過Linux層分發到PhoneWindowManager(系統進程)和ViewRootImpl(應用進程)。
  • 「分發順序」:PhoneWindowManager先執行,處理系統級的按鍵事件(如音量鍵、電源鍵等),ViewRootImpl后執行,處理應用層的按鍵事件(如方向鍵、回車鍵等)。
  • 「分發過程」:在ViewRootImpl中,存在一個名為InputStage的責任鏈,用于處理輸入事件,每個階段都可能對事件進行處理或將其傳遞給下一個階段。

/frameworks/base/core/java/android/view/ViewRootImpl.java

private int processKeyEvent(QueuedInputEvent q) {
    final KeyEvent event = (KeyEvent) q.mEvent;
    if (mUnhandledKeyManager.preViewDispatch(event)) {
        return FINISH_HANDLED;
    }

    // Deliver the key to the view hierarchy.
    if (mView.dispatchKeyEvent(event)) {
        return FINISH_HANDLED;
    }

    if (shouldDropInputEvent(q)) {
        return FINISH_NOT_HANDLED;
    }

    // This dispatch is for windows that don't have a Window.Callback. Otherwise,
    // the Window.Callback usually will have already called this (see
    // DecorView.superDispatchKeyEvent) leaving this call a no-op.
    if (mUnhandledKeyManager.dispatch(mView, event)) {
        return FINISH_HANDLED;
    }

    int groupNavigationDirection = 0;

    if (event.getAction() == KeyEvent.ACTION_DOWN
            && event.getKeyCode() == KeyEvent.KEYCODE_TAB) {
        if (KeyEvent.metaStateHasModifiers(event.getMetaState(), KeyEvent.META_META_ON)) {
            groupNavigationDirection = View.FOCUS_FORWARD;
        } else if (KeyEvent.metaStateHasModifiers(event.getMetaState(),KeyEvent.META_META_ON | KeyEvent.META_SHIFT_ON)) {
            groupNavigationDirection = View.FOCUS_BACKWARD;
        }
    }

    // If a modifier is held, try to interpret the key as a shortcut.
    if (event.getAction() == KeyEvent.ACTION_DOWN && !KeyEvent.metaStateHasNoModifiers(event.getMetaState()) && event.getRepeatCount() == 0
                    && !KeyEvent.isModifierKey(event.getKeyCode())
                    && groupNavigationDirection == 0) {
        if (mView.dispatchKeyShortcutEvent(event)) {
            return FINISH_HANDLED;
        }
        if (shouldDropInputEvent(q)) {
            return FINISH_NOT_HANDLED;
        }
    }

    // Apply the fallback event policy.
    if (mFallbackEventHandler.dispatchKeyEvent(event)) {
        return FINISH_HANDLED;
    }
    if (shouldDropInputEvent(q)) {
        return FINISH_NOT_HANDLED;
    }

    // Handle automatic focus changes.
    if (event.getAction() == KeyEvent.ACTION_DOWN) {
        if (groupNavigationDirection != 0) {
            if (performKeyboardGroupNavigation(groupNavigationDirection)) {
                return FINISH_HANDLED;
            }
        } else {
            if (performFocusNavigation(event)) {
                return FINISH_HANDLED;
            }
        }
    }
    return FORWARD;
}
  • 在處理按鍵事件之前,首先會調用mUnhandledKeyManager.preViewDispatch(event)來判斷是否有未處理的按鍵事件。如果有未處理的事件,則直接返回FINISH_HANDLED表示該事件已被處理。
  • 如果沒有未處理的事件,則調用mView.dispatchKeyEvent(event)將按鍵事件分發給View層次結構。如果View層次結構中的任何一個View處理了該事件,則直接返回FINISH_HANDLED表示該事件已被處理。
  • 如果按鍵事件不能被處理或應該被丟棄,則調用shouldDropInputEvent(q)方法來決定是否應該丟棄該事件。如果應該丟棄,則返回FINISH_NOT_HANDLED表示該事件未被處理;否則繼續處理該事件。
  • 如果事件仍未被處理,則調用mUnhandledKeyManager.dispatch(mView, event)來判斷是否有未處理的事件。如果有,則直接返回FINISH_HANDLED表示該事件已被處理。
  • 如果按鍵事件是一個特定的按鍵(如Tab鍵)并且同時滿足一些特定的條件,則設置groupNavigationDirection變量并調用performKeyboardGroupNavigation方法來處理自動的聚焦變化。
  • 如果按鍵事件是一個快捷鍵(即同時按下一個或多個修飾鍵和另一個鍵),則調用mView.dispatchKeyShortcutEvent(event)將事件分發給View層次結構來嘗試解釋該按鍵事件。如果該事件被處理,則返回FINISH_HANDLED表示該事件已被處理。
  • 如果事件仍未被處理,則調用mFallbackEventHandler.dispatchKeyEvent(event)應用回退事件策略來嘗試處理該事件。如果該事件被處理,則返回FINISH_HANDLED表示該事件已被處理。
  • 如果事件仍未被處理,則調用performFocusNavigation方法來處理自動的聚焦變化。如果該事件被處理,則返回FINISH_HANDLED表示該事件已被處理。
  • 最后,如果事件仍未被處理,則返回FORWARD表示該事件應該被傳遞給下一個事件處理程序。
private boolean performFocusNavigation(KeyEvent event) {
    int direction = 0;
    switch (event.getKeyCode()) {
        case KeyEvent.KEYCODE_DPAD_LEFT:
            if (event.hasNoModifiers()) {
                direction = View.FOCUS_LEFT;
            }
            break;
        case KeyEvent.KEYCODE_DPAD_RIGHT:
            if (event.hasNoModifiers()) {
                direction = View.FOCUS_RIGHT;
            }
            break;
        case KeyEvent.KEYCODE_DPAD_UP:
            if (event.hasNoModifiers()) {
                direction = View.FOCUS_UP;
            }
            break;
        case KeyEvent.KEYCODE_DPAD_DOWN:
            if (event.hasNoModifiers()) {
                direction = View.FOCUS_DOWN;
            }
            break;
        case KeyEvent.KEYCODE_TAB:
            if (event.hasNoModifiers()) {
                direction = View.FOCUS_FORWARD;
            } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
                direction = View.FOCUS_BACKWARD;
            }
            break;
    }
    if (direction != 0) {
        View focused = mView.findFocus();
        if (focused != null) {
            View v = focused.focusSearch(direction);
            if (v != null && v != focused) {
                // do the math the get the interesting rect
                // of previous focused into the coord system of
                // newly focused view
                focused.getFocusedRect(mTempRect);
                if (mView instanceof ViewGroup) {
                    ((ViewGroup) mView).offsetDescendantRectToMyCoords(focused, mTempRect);
                    ((ViewGroup) mView).offsetRectIntoDescendantCoords(v, mTempRect);
                }
                if (v.requestFocus(direction, mTempRect)) {
                    Log.i(TAG, "v.requestFocus == true");
                    boolean isFastScrolling = event.getRepeatCount() > 0;
                    playSoundEffect(SoundEffectConstants.getConstantForFocusDirection(direction,isFastScrolling));
                    return true;
                }
            }

            // Give the focused view a last chance to handle the dpad key.
            if (mView.dispatchUnhandledMove(focused, direction)) {
                return true;
            }
        } else {
            if (mView.restoreDefaultFocus()) {
                return true;
            }
        }
    }
    return false;
}

該方法用于處理焦點導航相關的按鍵事件,例如方向鍵和Tab鍵等。該方法接收一個KeyEvent對象作為參數,根據不同的按鍵碼和修飾符,計算出焦點導航的方向,然后嘗試在View樹中找到新的焦點,并將其設置為當前焦點。如果找到新的焦點并成功設置為當前焦點,則播放焦點變化時的聲音效果,并返回true表示焦點變化事件已被處理。如果沒有找到新的焦點,或者新的焦點不接受焦點設置請求,則返回false表示該事件未被處理。

/frameworks/base/core/java/com/android/internal/policy/DecorView.java

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
    final int keyCode = event.getKeyCode();
    final int action = event.getAction();
    final boolean isDown = action == KeyEvent.ACTION_DOWN;

    if (isDown && (event.getRepeatCount() == 0)) {
        // First handle chording of panel key: if a panel key is held
        // but not released, try to execute a shortcut in it.
        if ((mWindow.mPanelChordingKey > 0) && (mWindow.mPanelChordingKey != keyCode)) {
            boolean handled = dispatchKeyShortcutEvent(event);
            if (handled) {
                return true;
            }
        }

        // If a panel is open, perform a shortcut on it without the
        // chorded panel key
        if ((mWindow.mPreparedPanel != null) && mWindow.mPreparedPanel.isOpen) {
            if (mWindow.performPanelShortcut(mWindow.mPreparedPanel, keyCode, event, 0)) {
                return true;
            }
        }
    }

    if (!mWindow.isDestroyed()) {
        final Window.Callback cb = mWindow.getCallback();
        final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event) : super.dispatchKeyEvent(event);
        if (handled) {
            return true;
        }
    }
    boolean result = isDown ? mWindow.onKeyDown(mFeatureId, event.getKeyCode(), event) : mWindow.onKeyUp(mFeatureId, event.getKeyCode(), event);
    return result;
}

該方法用于處理按鍵事件的分發和處理,該方法接收一個KeyEvent對象,并提取出鍵碼和事件類型。如果該事件為按下事件并且重復次數為0,則執行以下操作:

  • 首先,處理面板按鍵的彈奏:如果面板按鍵已按下但未釋放,則嘗試在其中執行一個快捷方式。如果已處理該快捷方式,則返回true表示事件已處理。
  • 然后,如果面板已經打開,則在沒有面板按鍵的情況下執行其上的快捷方式。如果已處理該快捷方式,則返回true表示事件已處理。
  • 如果事件仍未被處理,則檢查Window對象是否已被銷毀,如果沒有,則獲取Window.Callback對象并將事件分派給它。如果已處理該事件,則返回true表示事件已處理。
  • 最后,如果事件仍未被處理,則將其傳遞給Window對象進行處理,并返回該事件是否為按下事件的結果。
public boolean superDispatchKeyEvent(KeyEvent event) {
    // Give priority to closing action modes if applicable.
    if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
        final int action = event.getAction();
        // Back cancels action modes first.
        if (mPrimaryActionMode != null) {
            if (action == KeyEvent.ACTION_UP) {
                mPrimaryActionMode.finish();
            }
            return true;
        }
    }

    if (super.dispatchKeyEvent(event)) {
        return true;
    }
    boolean handle = (getViewRootImpl() != null) && getViewRootImpl().dispatchUnhandledKeyEvent(event);
    return handle;
}

其作用是對KeyEvent事件進行分發處理。該方法首先判斷事件是否為返回鍵,如果是則優先處理當前的操作模式,如果存在操作模式則先結束操作模式,否則將事件交由父類ViewGroup進行處理。如果父類能夠處理該事件,則返回true,否則返回false,并將事件交由該DecorView 所對應的ViewRootImpl實例進行處理。

其中,getViewRootImpl()方法返回當前DecorView所在的ViewRootImpl實例。如果該實例存在,則調用dispatchUnhandledKeyEvent(event)方法進行處理,否則返回false。dispatchUnhandledKeyEvent(event)方法用于將該事件交由輸入法進行處理。

  1. 「View的事件處理」:
  • 「ViewGroup與View」:在Android中,ViewGroup是View的容器,負責分發事件給其子View。如果ViewGroup的dispatchTouchEvent方法返回true,事件被消費,不會傳遞給其onTouchEvent方法或子View。如果返回false,調用父控件的onTouchEvent方法或繼續傳遞給子View。
  • 「事件攔截」:ViewGroup有一個onInterceptTouchEvent方法,可以在事件傳遞給子View之前進行攔截。如果該方法返回true,則事件被攔截并在當前ViewGroup的onTouchEvent方法中處理。
  • 「事件消費」:無論是ViewGroup還是View,如果onTouchEvent方法返回true,表示事件被消費,不再傳遞給其他View或父控件。

/frameworks/base/core/java/android/app/Activity.java

public boolean dispatchKeyEvent(KeyEvent event) {
    onUserInteraction();

    // Let action bars open menus in response to the menu key prioritized over
    // the window handling it
    final int keyCode = event.getKeyCode();
    if (keyCode == KeyEvent.KEYCODE_MENU && mActionBar != null && mActionBar.onMenuKeyEvent(event)) {
        return true;
    }

    Window win = getWindow();
    if (win.superDispatchKeyEvent(event)) {
        return true;
    }
    View decor = mDecor;
    if (decor == null) decor = win.getDecorView();
    boolean handler = event.dispatch(this, decor != null ? decor.getKeyDispatcherState() : null, this);
    return handler;
}

該方法用于分發鍵事件,當用戶按下或釋放某個按鍵時,該方法將被調用。

  • 首先,方法調用onUserInteraction(),用于通知Activity用戶正在與應用程序交互。
  • 接著,方法檢查事件是否為菜單鍵事件,如果是,則首先檢查 ActionBar 是否存在,并且將事件傳遞給 ActionBar 的 onMenuKeyEvent() 方法進行處理。如果 ActionBar 成功處理該事件,則直接返回 true,表示事件已被處理。
  • 如果事件不是菜單鍵事件或者ActionBar無法處理該事件,則將事件傳遞給窗口處理,并返回窗口處理結果。如果窗口處理了該事件,則直接返回true,表示事件已被處理。
  • 如果事件既不是菜單鍵事件,也無法被窗口處理,則將事件分發給DecorView(該Activity 的根View),并返回DecorView的dispatchKeyEvent()方法的處理結果。

/frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

public boolean superDispatchKeyEvent(KeyEvent event) {
    return mDecor.superDispatchKeyEvent(event);
}

/frameworks/base/core/java/android/view/ViewGroup.java

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
    if (mInputEventConsistencyVerifier != null) {
        mInputEventConsistencyVerifier.onKeyEvent(event, 1);
    }

    if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
        if (super.dispatchKeyEvent(event)) {
            Log.e("ViewRootImpl","super.dispatchKeyEvent(event)");
            return true;
        }
    } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) {
        if (mFocused.dispatchKeyEvent(event)) {
            Log.e("ViewRootImpl","Focused.dispatchKeyEvent(event)");
            return true;
        }
    }

    if (mInputEventConsistencyVerifier != null) {
        mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
    }
    return false;
}

用于將按鍵事件分派到該ViewGroup及其子View。該方法首先通過檢查ViewGroup本身的狀態(是否擁有焦點且有邊界)來決定是否自己處理KeyEvent,如果ViewGroup本身滿足條件,則通過調用父類的dispatchKeyEvent方法處理事件,并返回true表示已處理。如果ViewGroup本身不滿足條件,則將KeyEvent分派到當前擁有焦點的子View,如果該子View處理了事件,則返回true表示已處理。如果KeyEvent最終未被處理,則返回false表示未處理。此方法還包含一些調試代碼,用于確保事件派發的一致性。

/frameworks/base/core/java/android/view/View.java

public boolean dispatchKeyEvent(KeyEvent event) {
    if (mInputEventConsistencyVerifier != null) {
        mInputEventConsistencyVerifier.onKeyEvent(event, 0);
    }

    // Give any attached key listener a first crack at the event.
    //noinspection SimplifiableIfStatement
    ListenerInfo li = mListenerInfo;
    if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) {
        Log.e("ViewRootImpl","mOnKeyListener.onKey");
        return true;
    }

    if (event.dispatch(this, mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null, this)) {
        Log.e("ViewRootImpl","event.dispatch");
        return true;
    }

    if (mInputEventConsistencyVerifier != null) {
        mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
    }
    return false;
}

該方法用于分派鍵盤事件到對應的視圖,并根據事件的處理結果返回一個布爾值。方法的參數event表示一個鍵盤事件,該事件將被分派到相應的視圖。方法中的第一步是調用mInputEventConsistencyVerifier.onKeyEvent(event, 0)方法來記錄鍵盤事件的一些基本信息,用于后續的事件一致性檢查。然后會首先調用視圖的OnKeyListener對象(如果有的話)的onKey 方法,如果該方法返回true,則表示該鍵盤事件被該監聽器處理,方法返回true,否則該鍵盤事件被傳遞給了該視圖的dispatch方法。在這里調用了event.dispatch(this, mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null, this)方法,該方法會根據鍵盤事件的類型,將其分發給視圖的onKeyDown或onKeyUp方法進行處理。如果該事件被處理了,則返回true,否則會調用mInputEventConsistencyVerifier.onUnhandledEvent(event, 0)方法記錄該事件未被處理的信息,并返回false表示該事件未被處理。

/frameworks/base/core/java/android/view/KeyEvent.java

public final boolean dispatch(Callback receiver, DispatcherState state, Object target) {
    switch (mAction) {
        case ACTION_DOWN: {
            mFlags &= ~FLAG_START_TRACKING;
            if (DEBUG) Log.v(TAG, "Key down to " + target + " in " + state + ": " + this);
            boolean res = receiver.onKeyDown(mKeyCode, this);
            if (state != null) {
                if (res && mRepeatCount == 0 && (mFlags&FLAG_START_TRACKING) != 0) {
                    if (DEBUG) Log.v(TAG, "  Start tracking!");
                    state.startTracking(this, target);
                } else if (isLongPress() && state.isTracking(this)) {
                    try {
                        if (receiver.onKeyLongPress(mKeyCode, this)) {
                            if (DEBUG) Log.v(TAG, "  Clear from long press!");
                            state.performedLongPress(this);
                            res = true;
                        }
                    } catch (AbstractMethodError e) {
                    }
                }
            }
            return res;
        }
        case ACTION_UP:
            if (DEBUG) Log.v(TAG, "Key up to " + target + " in " + state + ": " + this);
            if (state != null) {
                state.handleUpEvent(this);
            }
            return receiver.onKeyUp(mKeyCode, this);
        case ACTION_MULTIPLE:
            final int count = mRepeatCount;
            final int code = mKeyCode;
            if (receiver.onKeyMultiple(code, count, this)) {
                return true;
            }
            if (code != KeyEvent.KEYCODE_UNKNOWN) {
                mAction = ACTION_DOWN;
                mRepeatCount = 0;
                boolean handled = receiver.onKeyDown(code, this);
                if (handled) {
                    mAction = ACTION_UP;
                    receiver.onKeyUp(code, this);
                }
                mAction = ACTION_MULTIPLE;
                mRepeatCount = count;
                return handled;
            }
            return false;
    }
    return false;
}

KeyEvent事件分發的核心代碼,主要處理按鍵事件的分發。當一個按鍵事件被分發到一個View時,該View首先嘗試處理該事件。如果該View無法處理該事件,則事件將被分發給它的parent View或Activity,直到事件被處理或到達了View層級的最頂層。

  • 該方法根據KeyEvent的不同Action,分別進行處理。如果Action是ACTION_DOWN,即按下按鍵的事件,首先會調用Callback接口的onKeyDown方法來處理該事件,并根據事件處理的結果進行相應的處理。如果返回true,表示事件被成功處理,并且設置了FLAG_START_TRACKING標志位,則會調用DispatcherState的startTracking方法來開始追蹤該事件。如果事件是長按事件,且當前正在追蹤該事件,則會調用Callback接口的onKeyLongPress方法來處理長按事件。
  • 如果Action是ACTION_UP,即松開按鍵的事件,會調用Callback接口的onKeyUp方法來處理該事件,并根據DispatcherState是否存在,調用DispatcherState的handleUpEvent方法來結束追蹤該事件。
  • 如果Action是ACTION_MULTIPLE,即按鍵事件包含多個重復事件,會調用Callback接口的onKeyMultiple方法來處理該事件,并根據KeyEvent的repeatCount和keyCode信息,依次調用Callback接口的onKeyDown和onKeyUp方法來處理每一個重復事件,最后返回處理結果。

總的來說,KeyEvent類的dispatch方法實現了按鍵事件的分發和處理,為Android應用程序提供了豐富的按鍵事件處理能力。

  1. 「特殊情況」:
  • 「自定義處理」:可以通過重寫Activity、ViewGroup或View的dispatchKeyEvent、onInterceptTouchEvent、onTouchEvent等方法來自定義按鍵事件的處理邏輯。
  • 「外圍設備」:對于藍牙鍵盤、USB鍵盤等外圍設備,Android通過KeyEvent事件機制與它們進行交互。開發者可以通過重寫dispatchKeyEvent方法來截獲和處理這些設備發送的事件。

Key事件的分發邏輯是一個復雜但有序的過程,涉及事件的產生、分發和View的事件處理等多個階段。通過理解這個過程,可以更好地控制Android應用中按鍵事件的行為。

責任編輯:武曉燕 來源: 沐雨花飛蝶
相關推薦

2017-03-14 13:51:23

AndroidView事件分發和處理

2023-10-08 08:23:44

Android事件邏輯

2017-02-21 12:20:20

Android事件分發機制實例解析

2013-05-21 11:33:11

Android游戲開發按鍵中斷事件

2010-08-06 10:03:42

Flex事件

2016-12-08 10:19:18

Android事件分發機制

2010-08-06 10:24:56

Flex事件分發

2013-04-22 15:40:00

Android開發觸摸事件與點擊事件區別

2024-02-04 17:16:22

ReactVue前端

2013-05-14 11:08:23

AIR Android觸摸事件鼠標事件

2021-08-11 14:29:20

鴻蒙HarmonyOS應用

2010-08-09 11:14:36

Flex事件處理

2012-12-28 14:53:34

Android開發初始化窗體事件

2023-03-14 07:31:17

EoscGo語言

2023-04-03 08:39:33

中間件go語言

2021-08-03 06:57:36

Js事件節流

2012-05-07 09:10:30

Android SDK交互體驗功能按鍵事件

2024-06-25 08:43:25

C#編程模型

2023-11-01 07:55:03

事件監聽器傳遞數據

2013-04-24 11:15:56

Android開發Touch事件傳遞機制
點贊
收藏

51CTO技術棧公眾號

中文字幕中文在线| 一区二区免费在线观看| 超碰超碰超碰超碰| 成人aaaa| 欧美xfplay| 无人在线观看的免费高清视频| 又爽又大又黄a级毛片在线视频| 久久成人麻豆午夜电影| 久久免费视频在线观看| 性欧美精品男男| 99香蕉久久| 欧美午夜在线观看| av在线观看地址| 色网站免费在线观看| 成人深夜在线观看| 国产精品美女呻吟| 日韩乱码一区二区| 综合亚洲视频| 一本色道久久综合狠狠躁篇怎么玩| 手机av在线网站| 中文字幕系列一区| 五月天欧美精品| 69精品丰满人妻无码视频a片| 日色在线视频| 粉嫩aⅴ一区二区三区四区五区| 国产精品极品美女粉嫩高清在线| 亚洲国产综合久久| 你懂的成人av| 久久精品2019中文字幕| 人人人妻人人澡人人爽欧美一区| 国产精品极品| 日韩午夜三级在线| 日本中文字幕观看| 成人精品电影在线| 欧美性20hd另类| 人妻少妇精品无码专区二区| 在线黄色网页| 亚洲视频在线观看三级| 亚洲狠狠婷婷综合久久久| 天堂成人在线| 99久久综合色| 国产欧美在线一区二区| 亚洲av无码片一区二区三区| 国产在线不卡一卡二卡三卡四卡| 国产精品一区久久久| 亚洲高清视频免费观看| 老鸭窝毛片一区二区三区| 91国内产香蕉| 国产 欧美 日韩 在线| 午夜性色一区二区三区免费视频| xvideos亚洲人网站| 午夜黄色福利视频| 欧美jizz| 欧美成人免费网| 欧美黄片一区二区三区| 欧美日本一区二区视频在线观看 | 欧美精品高清视频| 粉色视频免费看| 日本免费一区二区三区等视频| 欧美伊人久久大香线蕉综合69| 精品一区二区中文字幕| 欧美人体一区二区三区| 91久久精品一区二区| 不卡影院一区二区| 巨胸喷奶水www久久久免费动漫| 色久优优欧美色久优优| 亚洲精品怡红院| 欧美成人xxxx| 欧美一区二区三区免费| 不许穿内裤随时挨c调教h苏绵| 日韩精品一区二区三区中文| 精品福利一区二区三区| 一区二区视频观看| 欧州一区二区| 美女久久久久久久| 日韩av在线天堂| 蜜桃av一区| 国产精品一区二区久久久| 国产精品久久久久久久久久久久久久久久| 国内精品不卡在线| 韩国一区二区三区美女美女秀 | www.xxxx精品| 青青草国产在线观看| 亚洲美女视频在线免费观看| 日本高清不卡的在线| 亚洲中文字幕在线观看| 国产**成人网毛片九色| 欧美日韩国产综合在线| 黄在线免费观看| 五月婷婷久久综合| 男女污污的视频| 国模大尺度视频一区二区| 亚洲国产成人爱av在线播放| 久久久久久国产免费a片| 中文精品电影| 日本一区二区在线免费播放| 国产精品视频在线观看免费| 99精品欧美一区二区三区综合在线| 日本一区二区三区免费观看| a黄色片在线观看| 欧美视频在线视频| 奇米777在线视频| 九九热爱视频精品视频| 欧美另类第一页| 天堂网一区二区| 成人动漫中文字幕| 9999在线观看| 写真福利精品福利在线观看| 日韩欧美成人激情| 欧美亚洲色综久久精品国产| 国内一区二区三区| 成人激情在线播放| 激情福利在线| 亚洲成人777| 一级黄色片国产| 国精一区二区| 91精品国产91久久久久久最新| 91久久国语露脸精品国产高跟| 99热99精品| h无码动漫在线观看| 国产毛片精品久久| 亚洲午夜av电影| 免费观看成人毛片| 波多野结衣中文字幕一区二区三区| 影音先锋在线亚洲| 久久野战av| 亚洲精品中文字幕女同| jizz国产免费| 粉嫩在线一区二区三区视频| av中文字幕av| 国产高清精品二区| 最近2019中文字幕大全第二页| 在线天堂中文字幕| 99在线精品免费| 大陆av在线播放| 91成人噜噜噜在线播放| 欧美成人精品xxx| 一区二区的视频| 国产精品国产成人国产三级| 亚洲欧美国产中文| 日韩在线中文| 国产精品香蕉国产| aⅴ在线视频男人的天堂| 在线观看一区二区视频| 成人国产精品久久久网站| 免费欧美日韩| 蜜桃日韩视频| 日本一道高清亚洲日美韩| 亚洲图片在线综合| 中文字幕 亚洲视频| 国产精品美女久久久久高潮| 91制片厂毛片| 国产精品国产一区| 91免费观看网站| 色女人在线视频| 欧美精品一区在线观看| 日本在线视频中文字幕| 91亚洲精品乱码久久久久久蜜桃| 国产亚洲欧美在线视频| 久操成人av| 国产精品在线看| caopo在线| 精品国产精品一区二区夜夜嗨| 精品少妇theporn| 91在线丨porny丨国产| 北条麻妃av高潮尖叫在线观看| 经典一区二区| 成人日韩在线电影| 黄色的视频在线观看| 日韩经典中文字幕在线观看| 波多野结衣高清在线| 国产精品久久久久婷婷| 国产黑丝在线视频| 国产日韩欧美三区| 婷婷四房综合激情五月| 国产午夜久久av| 97超级碰在线看视频免费在线看 | 欧美一级免费播放| 免费久久精品| 成人免费网站在线| 国产美女高潮在线| 综合网日日天干夜夜久久| 国产av精国产传媒| 精品成人av一区| 国产免费嫩草影院| 成人免费看的视频| 手机看片福利日韩| 欧美久久九九| 视频一区二区三区免费观看| 另类视频一区二区三区| 欧美一二三视频| 成人直播在线| 亚洲欧美日韩一区二区三区在线| 91福利在线观看视频| 午夜一区二区三区在线观看| 久久久久久久久福利| 成人中文字幕在线| 日本在线一二三区| 亚洲日本视频| 午夜啪啪福利视频| 国产麻豆精品久久| 国产精品一区二区欧美黑人喷潮水| 精品亚洲美女网站| 57pao成人国产永久免费| 麻豆电影在线播放| 亚洲天堂av电影| 亚洲国产精品久久人人爱潘金莲| 欧美在线观看一区二区| 日韩免费视频网站| 亚洲三级久久久| 亚洲精品国产熟女久久久| 国产99久久精品| 在线黄色免费看| 视频在线观看一区| av免费观看网| 亚洲国产高清一区二区三区| 在线精品日韩| jizzjizz欧美69巨大| 精品国产一区二区三区日日嗨| 国产午夜精品一区在线观看| 国产精品久久久久久影视| 国产污视频在线播放| 欧美老少配视频| 黄色在线论坛| 北条麻妃一区二区三区中文字幕| 极品白浆推特女神在线观看| 日韩av在线资源| 刘亦菲毛片一区二区三区| 91精品国产一区二区三区蜜臀| 中文字幕a级片| 色综合久久久网| 五月天婷婷久久| 欧美日韩亚洲一区二| 日韩精品乱码久久久久久| 一区二区三区在线免费视频| 日韩福利小视频| 亚洲色图在线视频| 国产日产精品一区二区三区的介绍| 国产香蕉久久精品综合网| 色欲av无码一区二区三区| 91丨porny丨蝌蚪视频| 日韩www视频| 成人一区在线看| youjizz.com日本| 成人免费视频caoporn| 美女搡bbb又爽又猛又黄www| 高清成人在线观看| 一级黄色免费视频| thepron国产精品| 中文字幕乱码一区| 91麻豆免费观看| 中文字幕人妻一区二区| 久久久久久久av麻豆果冻| 国产精品免费无码| 中国av一区二区三区| 久久av红桃一区二区禁漫| 中文字幕日韩av资源站| 成人免费精品动漫网站| 亚洲五月六月丁香激情| 久久夜靖品2区| 一本色道**综合亚洲精品蜜桃冫| 一级做a爰片久久毛片| 欧洲另类一二三四区| 国产精品国产三级国产普通话对白| 制服丝袜亚洲播放| 色网站免费观看| 亚洲欧美激情在线视频| 99re在线视频| 欧美猛少妇色xxxxx| 性欧美xxx69hd高清| 国产精品美女主播| 国产一区二区在线观| 国产专区一区二区三区| 狠狠做六月爱婷婷综合aⅴ| 欧美一级免费在线观看| 激情欧美国产欧美| 亚洲人成无码www久久久| 精品一区二区三区av| 日韩av手机在线播放| 欧美韩日一区二区三区四区| 爱爱视频免费在线观看| 天天综合色天天综合| 中文字幕人成人乱码亚洲电影| 欧美一区二区三区公司| 欧美日韩影视| 久久国产精品影片| 国产高清不卡| **亚洲第一综合导航网站| 亚洲精品进入| 国内自拍中文字幕| 视频一区二区中文字幕| 日本黄色三级网站| 99国产精品视频免费观看| 人妻无码一区二区三区免费| 亚洲午夜电影在线观看| 免费在线不卡av| 欧美va亚洲va香蕉在线| 在线看av的网址| 97超级碰碰人国产在线观看| 精品国产欧美| 日韩精品大片| 亚洲精品乱码久久久久久蜜桃麻豆| 亚洲最大综合网| 99久久99久久综合| 国产精品成人免费观看| 在线视频一区二区三区| 少妇精品视频一区二区| 久久夜色精品亚洲噜噜国产mv| 在线观看网站免费入口在线观看国内| 成人乱色短篇合集| 成人在线免费视频观看| 色欲av无码一区二区人妻| 国产精品18久久久久久久久 | 国产大片精品免费永久看nba| 在线精品国产亚洲| 亚洲一区二区在线看| 奶水喷射视频一区| 亚洲成年人在线观看| 亚洲欧美另类小说视频| 中文永久免费观看| 亚洲网址你懂得| 乡村艳史在线观看| 精品久久久久久一区| 亚洲成人资源| 国产吃瓜黑料一区二区| 亚洲视频一区在线| 国产乱子伦精品无码码专区| 在线精品91av| 激情亚洲影院在线观看| 欧美裸体网站| 久久av在线| 天堂久久精品忘忧草| 色哟哟精品一区| 欧美在线观看在线观看| 91精品国产免费久久久久久| 好吊妞视频这里有精品| 老子影院午夜伦不卡大全| 国产99精品在线观看| 国产亚洲精品成人| 精品国一区二区三区| 肉肉视频在线观看| 国产福利久久| 伊人成人在线| 亚洲欧美在线不卡| 欧美性xxxx| 风间由美一区| 国产精品亚洲精品| 99久久精品费精品国产风间由美| 欧美午夜aaaaaa免费视频| 亚洲国产精品成人综合| 中文字幕乱码人妻无码久久| 搡老女人一区二区三区视频tv| 男女啪啪999亚洲精品| 成人手机视频在线| 国产一区不卡精品| 久久久久久久久久91| 日韩av影视综合网| 激情开心成人网| 中文一区一区三区免费| 国产一区二区三区四区在线观看| avove在线播放| 亚洲精品99久久久久| 自拍偷自拍亚洲精品被多人伦好爽| 台湾成人av| 国产呦精品一区二区三区网站| 国模无码国产精品视频| 亚洲精品国产免费| 亚洲精品.com| 国产免费xxx| av成人老司机| 中文字幕第31页| 欧美激情久久久| 九一精品国产| 亚洲在线观看网站| 欧美日韩免费在线| 在线观看免费高清完整| 亚洲综合中文字幕68页| 亚洲视频www| 免费黄色国产视频| 精品国产乱码久久久久久浪潮| a一区二区三区| 桥本有菜av在线| 99国产精品国产精品毛片| 在线观看国产一区二区三区| 欧美激情一二区| 欧美美乳视频| 特黄特色免费视频| 日本乱人伦aⅴ精品| 欧美极品少妇videossex| 欧美日韩精品免费在线观看视频| 精品午夜一区二区三区在线观看 | 精品视频在线免费| 欧美黑人猛交的在线视频| 欧美亚洲一级二级| 国产精品白丝jk黑袜喷水| 日本视频免费观看| 欧美激情一区二区三区成人| 青草国产精品| 丰满大乳奶做爰ⅹxx视频 | 天天干天天操av|