[Android][Framework]系统手势和状态栏

PhoneWindowManager.java

PhoneWindowManager在init的时候会监听系统手势:

/** {@inheritDoc} */
@Override
public void init(Context context, IWindowManager windowManager,
                 WindowManagerFuncs windowManagerFuncs) {
...
// monitor for system gestures
mSystemGestures = new SystemGesturesPointerEventListener(context,
new SystemGesturesPointerEventListener.Callbacks() {
    @Override
    public void onSwipeFromTop() {
        if (mStatusBar != null) {
            requestTransientBars(mStatusBar);
        }
    }
    @Override
    public void onSwipeFromBottom() {
        if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_BOTTOM) {
            requestTransientBars(mNavigationBar);
        }
    }
    @Override
    public void onSwipeFromRight() {
        if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_RIGHT) {
            requestTransientBars(mNavigationBar);
        }
    }
    @Override
    public void onSwipeFromLeft() {
        if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_LEFT) {
            requestTransientBars(mNavigationBar);
        }
    }
    @Override
    public void onFling(int duration) {
        if (mPowerManagerInternal != null) {
            mPowerManagerInternal.powerHint(
                    PowerManagerInternal.POWER_HINT_INTERACTION, duration);
        }
    }
    @Override
    public void onDebug() {
        // no-op
    }
    @Override
    public void onDown() {
        mOrientationListener.onTouchStart();
    }
    @Override
    public void onUpOrCancel() {
        mOrientationListener.onTouchEnd();
    }
    @Override
    public void onMouseHoverAtTop() {
        mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
        Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
        msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
        mHandler.sendMessageDelayed(msg, 500);
    }
    @Override
    public void onMouseHoverAtBottom() {
        mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
        Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
        msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
        mHandler.sendMessageDelayed(msg, 500);
    }
    @Override
    public void onMouseLeaveFromEdge() {
        mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
    }
});
    ...
}

监听使用的是SystemGesturesPointerEventListener

/*
 * Listens for system-wide input gestures, firing callbacks when detected.
 * @hide
 */
public class SystemGesturesPointerEventListener implements PointerEventListener {

由注释可见,这个Listener监听系统级别的输入手势,由回调触发处理。

这个Listener实现了一个接口:

public interface PointerEventListener {
    /**
     * 1. onPointerEvent will be called on the service.UiThread.
     * 2. motionEvent will be recycled after onPointerEvent returns so if it is needed later a
     * copy() must be made and the copy must be recycled.
     **/
    public void onPointerEvent(MotionEvent motionEvent);
}

这个接口位于WindowManagerPolicy,是一个比较关键的接口。

回到Listener,看一下其对这个接口的具体实现:

@Override
public void onPointerEvent(MotionEvent event) {
    if (mGestureDetector != null && event.isTouchEvent()) {
        mGestureDetector.onTouchEvent(event);
    }
    switch (event.getActionMasked()) {
        case MotionEvent.ACTION_DOWN:
            mSwipeFireable = true;
            mDebugFireable = true;
            mDownPointers = 0;
            captureDown(event, 0);
            if (mMouseHoveringAtEdge) {
                mMouseHoveringAtEdge = false;
                mCallbacks.onMouseLeaveFromEdge();
            }
            mCallbacks.onDown();
            break;
        case MotionEvent.ACTION_POINTER_DOWN:
            captureDown(event, event.getActionIndex());
            if (mDebugFireable) {
                mDebugFireable = event.getPointerCount() < 5;
                if (!mDebugFireable) {
                    if (DEBUG) Slog.d(TAG, "Firing debug");
                    mCallbacks.onDebug();
                }
            }
            break;
        case MotionEvent.ACTION_MOVE:
            if (mSwipeFireable) {
                final int swipe = detectSwipe(event);
                mSwipeFireable = swipe == SWIPE_NONE;
                if (swipe == SWIPE_FROM_TOP) {
                    if (DEBUG) Slog.d(TAG, "Firing onSwipeFromTop");
                    mCallbacks.onSwipeFromTop();
                } else if (swipe == SWIPE_FROM_BOTTOM) {
                    if (DEBUG) Slog.d(TAG, "Firing onSwipeFromBottom");
                    mCallbacks.onSwipeFromBottom();
                } else if (swipe == SWIPE_FROM_RIGHT) {
                    if (DEBUG) Slog.d(TAG, "Firing onSwipeFromRight");
                    mCallbacks.onSwipeFromRight();
                } else if (swipe == SWIPE_FROM_LEFT) {
                    if (DEBUG) Slog.d(TAG, "Firing onSwipeFromLeft");
                    mCallbacks.onSwipeFromLeft();
                }
            }
            break;
        case MotionEvent.ACTION_HOVER_MOVE:
            if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
                if (!mMouseHoveringAtEdge && event.getY() == 0) {
                    mCallbacks.onMouseHoverAtTop();
                    mMouseHoveringAtEdge = true;
                } else if (!mMouseHoveringAtEdge && event.getY() >= screenHeight - 1) {
                    mCallbacks.onMouseHoverAtBottom();
                    mMouseHoveringAtEdge = true;
                } else if (mMouseHoveringAtEdge
                        && (event.getY() > 0 && event.getY() < screenHeight - 1)) {
                    mCallbacks.onMouseLeaveFromEdge();
                    mMouseHoveringAtEdge = false;
                }
            }
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            mSwipeFireable = false;
            mDebugFireable = false;
            mCallbacks.onUpOrCancel();
            break;
        default:
            if (DEBUG) Slog.d(TAG, "Ignoring " + event);
    }
}

其中mCallbacks就是

interface Callbacks {
    void onSwipeFromTop();
    void onSwipeFromBottom();
    void onSwipeFromRight();
    void onSwipeFromLeft();
    void onFling(int durationMs);
    void onDown();
    void onUpOrCancel();
    void onMouseHoverAtTop();
    void onMouseHoverAtBottom();
    void onMouseLeaveFromEdge();
    void onDebug();
}

即定义好的10种手势。

里面switch语句处理的操作也是MotionEvent最基本的操作。这里主要看一下从上往下滑动的事件是怎么计算的:

case MotionEvent.ACTION_MOVE:
    if (mSwipeFireable) {
        final int swipe = detectSwipe(event);
        mSwipeFireable = swipe == SWIPE_NONE;
        if (swipe == SWIPE_FROM_TOP) {
            if (DEBUG) Slog.d(TAG, "Firing onSwipeFromTop");
            mCallbacks.onSwipeFromTop();
  1. 在MotionEvent.ACTION_DOWN的时候,将mSwipeFireable置为true
  2. 通过detectSwipe()方法计算滑动方向
  3. 确定SWIPE_FROM_TOP事件,调用对应回调

来看看detectSwipe方法,具体见注释。

private int detectSwipe(MotionEvent move) {
    // 返回此event中历史的点数
    final int historySize = move.getHistorySize();
    final int pointerCount = move.getPointerCount();
    for (int p = 0; p < pointerCount; p++) {
        final int pointerId = move.getPointerId(p);
        final int i = findIndex(pointerId);
        if (i != UNTRACKED_POINTER) {
            for (int h = 0; h < historySize; h++) {
                // 两次事件的间隔
                final long time = move.getHistoricalEventTime(h);
                final float x = move.getHistoricalX(p, h);
                final float y = move.getHistoricalY(p,  h);
                final int swipe = detectSwipe(i, time, x, y);
                if (swipe != SWIPE_NONE) {
                    return swipe;
                }
            }
            final int swipe = detectSwipe(i, move.getEventTime(), move.getX(p), move.getY(p));
            if (swipe != SWIPE_NONE) {
                return swipe;
            }
        }
    }
    return SWIPE_NONE;
}

private int detectSwipe(int i, long time, float x, float y) {
    final float fromX = mDownX[i];
    final float fromY = mDownY[i];
    final long elapsed = time - mDownTime[i];
    if (DEBUG) Slog.d(TAG, "pointer " + mDownPointerId[i]
            + " moved (" + fromX + "->" + x + "," + fromY + "->" + y + ") in " + elapsed);
    if (fromY <= mSwipeStartThreshold/*status_bar_height 意味着从status_bar范围内开始*/
            && y > fromY + mSwipeDistanceThreshold/*status_bar_height 划出status_bar范围*/
            && elapsed < SWIPE_TIMEOUT_MS/*500ms*/) {
        return SWIPE_FROM_TOP;
    }
    if (fromY >= screenHeight - mSwipeStartThreshold
            && y < fromY - mSwipeDistanceThreshold
            && elapsed < SWIPE_TIMEOUT_MS) {
        return SWIPE_FROM_BOTTOM;
    }
    if (fromX >= screenWidth - mSwipeStartThreshold
            && x < fromX - mSwipeDistanceThreshold
            && elapsed < SWIPE_TIMEOUT_MS) {
        return SWIPE_FROM_RIGHT;
    }
    if (fromX <= mSwipeStartThreshold
            && x > fromX + mSwipeDistanceThreshold
            && elapsed < SWIPE_TIMEOUT_MS) {
        return SWIPE_FROM_LEFT;
    }
    return SWIPE_NONE;
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏知识分享

Android之网络摄像头

实现的功能就是两个手机在一个局域网内可以互相观看对方的摄像头图像,当然如果都是连接公网那么就能远程互看了,,,,和视频聊天差不多,,不过没有声音,,,,,,,,...

7418
来自专栏每日一篇技术文章

VR+全景播放器+头控讲解-06

在UIView上面布局我们可以使用UIButton UIView UIImageView等,但是是在3D场景中,我们不能使用UIView,我们要使用平面几何当视...

831
来自专栏james大数据架构

Android中Services之异步IntentService

IntentService:异步处理服务,新开一个线程:handlerThread在线程中发消息,然后接受处理完成后,会清理线程,并且关掉服务。 IntentS...

1946
来自专栏移动开发的那些事儿

Android事件分发原理分析

在Android中,触碰控件的时候回产生一个ACTION_DOWN事件并逐层向下传递,首先ACTION_DOWN回先从Activity的dispatchTouc...

1063
来自专栏开发之途

Android 解决 View 的滑动冲突

关于 Android 的 TouchEvent 事件分发机制可以看这里:Java_Android_Learn,本文讲解的是如何去解决 View 之间的滑动冲突

1171
来自专栏懒人开发

dispatchTouchEvent事件分发浅析(二)分发

具体代码可以见https://github.com/2954722256/demo_event

1413
来自专栏向治洪

android viewgroup事件分发机制

今天给大家代码ViewGroup事件分发的源码解析~~凡是自定义ViewGroup实现各种滑动效果的,不可避免的会出现很多事件的冲突,对ViewGroup事件分...

2066
来自专栏CodingBlock

Android查缺补漏(View篇)--事件分发机制源码分析

在上一篇博文中分析了事件分发的流程及规则,本篇会从源码的角度更进一步理解事件分发机制的原理,如果对事件分发规则还不太清楚的童鞋,建议先看一下上一篇博文 《And...

4037
来自专栏向治洪

图片缩放,拖拽等操作

之前做项目要对图片的查看,然后就自己写了一个,适合对图片的浏览,跟系统图库的效果一样哦,先贴一张美女图片,听说有美女,男人就会多看一眼,不知道是不是真的,哈哈 ...

2956
来自专栏懒人开发

dispatchTouchEvent事件分发浅析(四)Intercept拦截

上一篇,我们大体理解了分发的过程,并且简单做了点击,分析了执行顺序 这篇我们来看下 Intercept拦截

902

扫码关注云+社区

领取腾讯云代金券