精品欧美一区二区三区在线观看 _久久久久国色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技術棧公眾號

999精品视频在线观看| 免费在线观看黄| 美日韩精品视频| 色青青草原桃花久久综合| 在线免费黄色网| 黄色小说在线播放| 国产农村妇女毛片精品久久麻豆| 国产欧美中文字幕| 久久久久亚洲天堂| 精品久久影院| 亚洲国产婷婷香蕉久久久久久 | 国产极品一区二区| 素人啪啪色综合| 激情久久av一区av二区av三区| 视频在线一区二区三区| 亚洲国产精彩视频| 麻豆成人综合网| 69久久夜色精品国产69乱青草| 蜜桃av免费观看| 欧美做受69| 欧美v日韩v国产v| 色噜噜狠狠一区二区| 国产99在线观看| 综合色天天鬼久久鬼色| 日韩中文一区二区三区| 手机看片1024日韩| 国产精品一品视频| 国产自产女人91一区在线观看| 久久国产精品系列| 午夜电影亚洲| 日韩中文综合网| 中国极品少妇videossexhd| 亚洲伊人精品酒店| 欧美无砖专区一中文字| aa在线免费观看| 51漫画成人app入口| 亚洲狠狠丁香婷婷综合久久久| 日韩精品久久久免费观看| 深爱激情五月婷婷| 成人中文字幕合集| 91丨九色丨国产| 国产又大又粗又硬| 精品一二线国产| 国产精品一二区| 中文永久免费观看| 日韩二区在线观看| 欧洲亚洲女同hd| 日韩av大片在线观看| 亚洲第一黄色| 2018中文字幕一区二区三区| 欧美亚韩一区二区三区| 妖精视频成人观看www| 久久久亚洲成人| 日本三级网站在线观看| 一区在线免费观看| 97视频免费观看| 日韩精品在线免费视频| 一本久久综合| 欧美洲成人男女午夜视频| 国产亚洲欧美在线精品| 狂野欧美一区| 91精品久久久久久久久青青| 国产又黄又粗又长| 国产成人鲁色资源国产91色综| 91九色在线观看| 亚洲成人中文字幕在线| 波多野结衣中文一区| 国产尤物99| 免费成人av电影| 国产精品无码永久免费888| 亚洲国产欧美一区二区三区不卡| 天堂а√在线资源在线| 亚洲私人黄色宅男| 国产肉体ⅹxxx137大胆| а√天堂8资源在线| 黑人巨大精品欧美一区二区| 国产精品亚洲a| 久久精品黄色| 精品毛片乱码1区2区3区| 亚洲观看黄色网| 日韩dvd碟片| 欧美激情奇米色| 青草视频在线观看免费| 老司机午夜精品| 国产成人成网站在线播放青青| 亚洲欧洲综合在线| 国产精品无码永久免费888| 亚洲中文字幕无码一区二区三区| 岛国在线视频网站| 欧美色图第一页| 欧美一级免费在线| 九九久久婷婷| 欧美成人激情在线| 日本特级黄色片| 国产精品一二三四区| 蜜桃日韩视频| 欧美大胆的人体xxxx| 日本精品视频一区二区| 三级黄色片免费看| 奇米亚洲欧美| 久久人人97超碰精品888| 国产99免费视频| 成人网在线免费视频| 亚洲免费在线精品一区| 后进极品白嫩翘臀在线播放| 欧美在线高清视频| 午夜不卡久久精品无码免费| 日韩欧美一区二区三区在线视频| 久久久久久久久国产| 又污又黄的网站| 99在线精品观看| 黄色一级视频播放| 欧美色999| 亚洲国产精品成人av| 国产人妻精品一区二区三区不卡 | 久久精品一区二| jizz性欧美2| 久久国内精品一国内精品| 欧美videossex极品| 国产凹凸在线观看一区二区| 亚洲一区二区不卡视频| 亚洲私拍视频| 亚洲成人网久久久| 免费看一级一片| 精品一区二区影视| 亚洲精品一区二区三区四区五区| 亚洲啊v在线| 精品播放一区二区| 国产一级免费av| 国产一区二区免费视频| 午夜精品短视频| 欧美日韩大片| 亚洲伦理中文字幕| 国产一级精品视频| 北条麻妃国产九九精品视频| 97免费视频观看| 亚洲国产aⅴ精品一区二区| 北条麻妃一区二区三区中文字幕 | 日韩激情电影| 亚洲国产精久久久久久| 久久精品视频6| 国产91精品一区二区| 欧美另类videosbestsex日本| 黄色成人小视频| 综合136福利视频在线| 亚洲大片免费观看| 久久影院电视剧免费观看| 久久综合九色综合88i| 国产精品xxx在线观看| 欧美国产欧美亚洲国产日韩mv天天看完整 | 免费a级毛片在线观看| 欧美日韩中文字幕日韩欧美| 人妻丰满熟妇av无码久久洗澡| 一本久道综合久久精品| 玛丽玛丽电影原版免费观看1977| 精品众筹模特私拍视频| 亚洲成人久久久久| 97久久久久久久| 久久久久国产精品厨房| 女性隐私黄www网站视频| 国产成人调教视频在线观看| 国产成人亚洲综合| 98在线视频| 欧美丰满少妇xxxxx高潮对白| 国产一区二区播放| 成人免费av在线| 久久成人免费观看| 成人在线免费小视频| 国产一区私人高清影院| 中文在线免费| 亚洲国模精品一区| 亚洲 欧美 中文字幕| 国产精品你懂的| 国产一级二级av| 国产美女一区| 亚洲免费久久| 成人爽a毛片免费啪啪红桃视频| 2020国产精品视频| 99青草视频在线播放视| 日韩视频免费观看高清完整版在线观看| 国产亚洲精品码| 久久久国产综合精品女国产盗摄| 污污动漫在线观看| 国产精品s色| 欧美重口乱码一区二区| 91麻豆精品| 91chinesevideo永久地址| 国产高清视频在线观看| 欧美一区二区三区免费在线看| 中文字幕一区二区三区手机版| 久久嫩草精品久久久精品一| 毛片毛片毛片毛| 亚洲巨乳在线| 一卡二卡3卡四卡高清精品视频| 日本高清精品| 国产精品看片资源| 久草在线视频网站| 色七七影院综合| 亚洲欧美色视频| 欧美一级欧美三级在线观看 | 性色一区二区| 欧美日韩一级在线| 九九热精品视频在线观看| 91青青草免费在线看| 最新欧美电影| 久久人人看视频| 麻豆电影在线播放| 亚洲欧洲国产精品| 神马午夜在线观看| 欧美一级艳片视频免费观看| 日本熟女毛茸茸| 亚洲国产毛片aaaaa无费看| 国产日韩精品中文字无码| 99国产精品久久久久久久久久久 | 大胆人体色综合| 国产裸舞福利在线视频合集| 欧美精品一区二区三区很污很色的| 最新中文字幕免费| 欧美日韩国产页| 久久久无码一区二区三区| 综合久久久久综合| 亚洲女人毛茸茸高潮| 2020国产成人综合网| 国产精品亚洲一区二区无码| 国产一区二区三区美女| 美女网站色免费| 三级久久三级久久| 六月丁香婷婷在线| 国产欧美日韩一级| 日韩中字在线观看| 最新日韩欧美| 91黄色在线看| 亚洲性色视频| 高清无码视频直接看| 亚洲精品网址| 99精品一区二区三区的区别| 青草国产精品| 天天久久人人| 成久久久网站| 婷婷五月色综合| 欧美日韩在线播放视频| 日本在线成人一区二区| 精品国产网站| 亚洲草草视频| 四季av一区二区三区免费观看| 日韩少妇中文字幕| 欧洲激情视频| 中国人体摄影一区二区三区| 久久在线播放| 99亚洲精品视频| 重囗味另类老妇506070| 欧美 日韩 国产精品| 国产精品a级| 亚洲不卡中文字幕无码| 国产亚洲综合精品| 国产美女三级视频| 久久狠狠亚洲综合| 亚洲综合123| 国产精品123| 久久人人爽人人人人片| 久久影音资源网| 亚洲精品视频网址| 亚洲欧美一区二区三区国产精品| 亚洲av鲁丝一区二区三区| 亚洲国产精品久久人人爱| 久久久久久久久久免费视频 | 国产精品福利一区| 日韩视频中文字幕在线观看| 亚洲一二三区在线观看| 欧美一级视频免费观看| 欧美亚洲国产一区二区三区va| 国产精品久久久久久久成人午夜| 日韩一区二区电影网| 熟妇人妻系列aⅴ无码专区友真希| 日韩精品视频在线播放| 丁香在线视频| 九九热精品在线| 美女100%一区| 亚洲精品欧美极品| 天天操综合520| 影音先锋亚洲视频| 影音先锋久久资源网| 男女视频一区二区三区| 国产酒店精品激情| 水蜜桃av无码| 亚洲欧美在线aaa| 国产一级特黄视频| 欧美性极品少妇| 狠狠综合久久av一区二区| 亚洲人成在线免费观看| 超碰免费公开在线| 欧美最猛性xxxx| 国产一区二区av在线| 久久久一本精品99久久精品| 91精品国产麻豆国产在线观看 | 激情在线视频播放| 日本精品一区二区三区在线 | 欧美在线日韩精品| 狠狠入ady亚洲精品| 91小视频网站| 91首页免费视频| 一区视频免费观看 | 在线观看免费视频a| 亚洲国产小视频在线观看| 国产一二区在线| 日本欧美精品在线| 成人h动漫精品一区二区器材| 日韩亚洲视频在线| 国产精品久久久久9999高清| www.久久av.com| 国产亚洲精品资源在线26u| 成人免费看片98| 制服丝袜国产精品| av中文天堂在线| 1769国内精品视频在线播放| 久久综合偷偷噜噜噜色| 视频在线99| 久久xxxx| 亚洲男人在线天堂| 一区二区三区在线观看欧美| 中文字幕一区二区三区四区免费看| 亚洲国产成人av在线| 在线观看av免费| 成人午夜在线观看| 欧美gay男男猛男无套| 精品免费国产一区二区| 成人国产精品免费| 九九热只有精品| 日韩一区二区免费在线观看| 麻豆91在线| 国产一区在线播放| 日韩午夜电影网| 一本色道久久亚洲综合精品蜜桃| 26uuu国产日韩综合| 国产91av视频| 亚洲国产精品成人精品| 9765激情中文在线| 国产传媒一区| 亚洲精选国产| 国产精品边吃奶边做爽| 欧美三级xxx| 国产在线色视频| 国产精品久久久久久久美男| 精品毛片免费观看| 亚洲这里只有精品| 中文字幕一区三区| 国产sm主人调教女m视频| 久久精品国产亚洲精品2020| 亚洲资源在线| www国产免费| 国产成人高清视频| 国产一级片视频| 日韩av在线导航| 成人自拍av| 中文字幕中文字幕一区三区| 国产综合色产在线精品| 国产精品三区在线观看| 欧美zozozo| 麻豆蜜桃在线观看| 日韩国产欧美一区| 黄网站免费久久| 国产成人精品av久久| 亚洲国产天堂久久综合| av有声小说一区二区三区| 午夜精品一区二区三区在线观看 | 免费看a在线观看| 成人免费观看网站| 亚洲欧美网站| 伊人影院综合网| 日韩小视频在线观看专区| 国产第一页在线| 欧美在线播放一区二区| 经典三级在线一区| 精品一区免费观看| 亚洲色图美腿丝袜| 色综合久久久| 天堂…中文在线最新版在线| 国产色产综合产在线视频| 一区二区三区精彩视频| 久久久久国产精品免费网站| 亚洲成aⅴ人片久久青草影院| 中文字幕第36页| 亚洲五码中文字幕| 福利视频在线播放| av观看久久| 日本在线不卡视频一二三区| 人妻久久一区二区| 亚洲欧美中文日韩在线| 久久9999免费视频| 久久精品99国产| 亚洲精品视频一区二区| 欧美日本韩国一区二区| 91九色单男在线观看| 亚洲欧美视频| 校园春色 亚洲| 国产午夜精品全部视频播放| 日韩免费高清视频网站| 在线观看高清免费视频| 一区二区免费看| 日本免费视频在线观看|