Android系统启动篇

1,《android系统启动流程简介》

2,《android init进程启动流程》

3,《android zygote进程启动流程》

4,《Android SystemServer进程启动流程》

5,《android launcher启动流程》

6,《Android Activity启动过程详解》

Android系统开发准备篇

1,《Android 源码下载和编译》

2,《android 11源码编译和pixel3 刷机》

3,《Android Framework代码IDE加载和调试》

Android系统开发实践篇

1,《android设置默认输入法》

2,《android framework预制APK应用》

3,《Android系统层面限制应用开机自启动详解》

4,《android单独编译framework模块并push》

5,《Android Framework开发系统问题分析》

Android系统开发核心知识储备篇

1,《Android编译系统-envsetup和lunch代码篇》

2,《Android编译系统-概念篇》

3,《android日志系统详解》

4,《Android系统Handler详解》

5,《Android系统Binder详解》

6,《Android中Activity、View和Window关系详解》

7,《android view绘制流程详解》

8,《Android读取系统属性详解》

9,《android 窗口管理机制详解》

10,《初识Android系统》

11,《android中AMS进程通知Zygote进程fork新进程的通信方式》

Android核心功能详解篇

1,《android应用市场点击下载APK安装详解》

2,《Android 手势导航(从下往上滑动进入多任务页面)》

3,《android手势分析(应用界面左往右边滑动退出应用)》

4,《android应用安装流程详解》

5,《android11安装应用触发桌面图标刷新流程》

6,《Android系统多任务Recents详解》

7,《android系统导航栏视图分析》

———————————————————————————————————————————

一、如何找到入口

        Android10推出了全新的手势导航功能,原生的Android系统就提供了此功能,根据这个切入点查询相关实现,Android 10和11的源码里面,在SystemUI 模块里面可以找到对应的关键代码类如下:

SystemUI\src\com\android\systemui\statusbar\phone\EdgeBackGestureHandler.java
SystemUI\src\com\android\systemui\statusbar\phone\NavigationBarEdgePanel.java 

        EdgeBackGestureHandler.java,这个类是整个返回手势的核心管理类,EdgeBackGestureHandler 类的初始化,以及调用过程,放在 SystemUI\src\com\android\systemui\statusbar\phone\NavigationBarView.java 中实现的,具体逻辑如下:

// SystemUI\src\com\android\systemui\statusbar\phone\NavigationBarView.java
public NavigationBarView(Context context, AttributeSet attrs) {
        super(context, attrs);
        ... ...
        // 构造方法中实例化EdgeBackGestureHandler对象
        mEdgeBackGestureHandler = new EdgeBackGestureHandler(context, mOverviewProxyService,
                mSysUiFlagContainer, mPluginManager, this::updateStates);
}
 
 @Override
public void onNavigationModeChanged(int mode) {
   ... ...
   // 系统导航模式发生变化时回调 (全屏手势导航/按键导航)
   mEdgeBackGestureHandler.onNavigationModeChanged(mNavBarMode);
   ... ...
}
 
@Override
protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    ... ...
    // 当NavigationBarView 回调onAttachedToWindow() 时,回调onNavBarAttached(),保持add
    // 到window 的时机一致
    mEdgeBackGestureHandler.onNavBarAttached();
    ... ...
}
@Override
protected void onDetachedFromWindow() {
    super.onDetachedFromWindow();
    ... ...
    // 移除
    mEdgeBackGestureHandler.onNavBarDetached();
    ... ...
}

EdgeBackGestureHandler内部关键代码,注册input事件监听器,实例化NavigationBarEdgePanel

// SystemUI\src\com\android\systemui\statusbar\phone\EdgeBackGestureHandler.java
    
    // 定义一个 input 事件 Reciever
    class SysUiInputEventReceiver extends InputEventReceiver {
        SysUiInputEventReceiver(InputChannel channel, Looper looper) {
            super(channel, looper);
        }
 
        public void onInputEvent(InputEvent event) {
            EdgeBackGestureHandler.this.onInputEvent(event);
            finishInputEvent(event, true);
        }
    }
    
    // 更新返回手势控制器的状态
    // 此方法调用时机:
    // 1、EdgeBackGestureHandler.onUserSwitched()
    // 2、EdgeBackGestureHandler.onNavBarAttached()
    // 3、EdgeBackGestureHandler.onNavBarDetached()
    // 4、EdgeBackGestureHandler.onNavigationModeChanged()
   private void updateIsEnabled() {
        boolean isEnabled = mIsAttached && mIsGesturalModeEnabled;
        ... ...
        if (!mIsEnabled) {
            ... ...
            // Register input event receiver
            // 通过 InputMonitor 实现全局手势监听
            mInputMonitor = InputManager.getInstance().monitorGestureInput(
                    "edge-swipe", mDisplayId);
            mInputEventReceiver = new SysUiInputEventReceiver(
                    mInputMonitor.getInputChannel(), Looper.getMainLooper());
 
            // Add a nav bar panel window
            // 添加 NavigationBarEdgePanel 
            setEdgeBackPlugin(new NavigationBarEdgePanel(mContext));
            ... ...  
        }
    }
    
    // NavigationBarEdgePanel extends NavigationEdgeBackPlugin
    private void setEdgeBackPlugin(NavigationEdgeBackPlugin edgeBackPlugin) {
        if (mEdgeBackPlugin != null) {
            mEdgeBackPlugin.onDestroy();
        }
        mEdgeBackPlugin = edgeBackPlugin;
        // 添加回调,NavigationBarEdgePanel 与 当前类通信
        mEdgeBackPlugin.setBackCallback(mBackCallback);
        // 创建NavigationBarEdgePanel 参数,并未显示
        mEdgeBackPlugin.setLayoutParams(createLayoutParams());
        ... ...
    }

二、手势导航(返回)流程整理

  1. 在NavigationBarView 构造方法中 初始化 EdgeBackGestureHandler 对象 ,并且在在 NavigationBarView 的 onNavigationModeChanged()、onAttachedToWindow() 、onDetachedFromWindow() 中调用 EdgeBackGestureHandler 的对应方法,调用之后,最后会走到 EdgeBackGestureHandler 的 updateIsEnabled() 方法;
  2. EdgeBackGestureHandler. updateIsEnabled() 方法中实例化 实例化InputMonitor 对象,并且注册 InputEventReceive监听事件,实现input 事件监听,同时 初始化 NavigationBarEdgePanel ,添加到windwow TIPS:此时NavigationBarEdgePanel 还是不显示的状态
  3. 监听InputEventReceiver.onInputEvent() 方法回调,实现输入事件处理逻辑。

三、输入事件核心处理逻辑

在 InputEventReceiver.onInputEvent() 中,进入到自定义的处理逻辑中:

 private void onMotionEvent(MotionEvent ev) {
        int action = ev.getActionMasked();
        if (action == MotionEvent.ACTION_DOWN) {
            // Verify if this is in within the touch region and we aren't in immersive mode, and
            // either the bouncer is showing or the notification panel is hidden
            // 判断是否是左边滑动
            mIsOnLeftEdge = ev.getX() <= mEdgeWidthLeft + mLeftInset;
            mMLResults = 0;
            mLogGesture = false;
            mInRejectedExclusion = false;
            // 看是否开启了此功能,并且判断是否在排除区域
            mAllowGesture = !mDisabledForQuickstep && mIsBackGestureAllowed
                    && !mGestureBlockingActivityRunning
                    && !QuickStepContract.isBackGestureDisabled(mSysUiFlags)
                    && isWithinTouchRegion((int) ev.getX(), (int) ev.getY());
            // 把 MotionEvent 传递给 NavigationBarEdgePanel 处理
            if (mAllowGesture) {
                mEdgeBackPlugin.setIsLeftPanel(mIsOnLeftEdge);
                mEdgeBackPlugin.onMotionEvent(ev);
            }
           ... ... 
        } else if (mAllowGesture || mLogGesture) {
            if (!mThresholdCrossed) {
                mEndPoint.x = (int) ev.getX();
                mEndPoint.y = (int) ev.getY();
                // 多点触碰的情况,直接取消当前 input事件
                if (action == MotionEvent.ACTION_POINTER_DOWN) {
                    if (mAllowGesture) {
                        logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_MULTI_TOUCH);
                        // We do not support multi touch for back gesture
                        cancelGesture(ev);
                    }
                    mLogGesture = false;
                    return;
                } else if (action == MotionEvent.ACTION_MOVE) {
                    // 筛选不合格的其他 输入事件
                    if ((ev.getEventTime() - ev.getDownTime()) > mLongPressTimeout) {
                        if (mAllowGesture) {
                            logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_LONG_PRESS);
                            cancelGesture(ev);
                        }
                        mLogGesture = false;
                        return;
                    }
                    float dx = Math.abs(ev.getX() - mDownPoint.x);
                    float dy = Math.abs(ev.getY() - mDownPoint.y);
                    if (dy > dx && dy > mTouchSlop) {
                        if (mAllowGesture) {
                            logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_VERTICAL_MOVE);
                            cancelGesture(ev);
                        }
                        mLogGesture = false;
                        return;
                    } else if (dx > dy && dx > mTouchSlop) {
                        if (mAllowGesture) {
                            mThresholdCrossed = true;
                            // Capture inputs
                            // 捕获当前 手势,防止干扰界面
                            mInputMonitor.pilferPointers();
                        } else {
                            logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_FAR_FROM_EDGE);
                        }
                    }
                }
            }
            if (mAllowGesture) {
                // forward touch
                mEdgeBackPlugin.onMotionEvent(ev);
            }
        }
    ... ...
    }
    
  // frameworks/base/core/java/android/view/InputMonitor.java
  /**
     * Takes all of the current pointer events streams that are currently being sent to this
     * monitor and generates appropriate cancellations for the windows that would normally get
     * them.
     *
     * This method should be used with caution as unexpected pilfering can break fundamental user
     * interactions.
     */    
     public void pilferPointers() {
            try {
                mHost.pilferPointers();
           } catch (RemoteException e) {            
            e.rethrowFromSystemServer();
        }
    }  

可看出 NavigationBarEdgePanel 就是一个 自定义view,根据 控制器 传递过来的 MotionEvent 实现具体的UI 效果,并回传事件。

@Override
public void onMotionEvent(MotionEvent event) {
    // MotionEvent 预处理逻辑
    ... ...
    switch (event.getActionMasked()) {
        case MotionEvent.ACTION_DOWN:
            ... ...
            setVisibility(VISIBLE);
            // 记录dwon初始坐标点信息
            ... ... 
            break;
        case MotionEvent.ACTION_MOVE:
            handleMoveEvent(event);
            break;
        case MotionEvent.ACTION_UP:
            // 手势抬起,回调
            if (mTriggerBack) {
                triggerBack();
            } else {
                cancelBack();
            }
           ... ...
            break;
        case MotionEvent.ACTION_CANCEL:
            cancelBack();
            ... ...
            break;
        default:
            break;
    }
}

        其中,move状态下的 handleMoveEvent()是主要的处理逻辑:判断 x 轴的 offset 数值是否达到了阈值 mSwipeThreshold,从而 回调 BackCallback 事件 和当前视图的更新,

private void handleMoveEvent(@NonNull MotionEvent event) {
    float x = event.getX();
    float y = event.getY();
    ... ...
    // Apply a haptic on drag slop passed
    // 已经超过阈值的话
    // 设置达到触发返回事件条件
    if (!mDragSlopPassed && touchTranslation > mSwipeThreshold) {
        mDragSlopPassed = true;
        mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
        mVibrationTime = SystemClock.uptimeMillis();
        // Let's show the arrow and animate it in!
        mDisappearAmount = 0.0f;
        setAlpha(1f);
        // And animate it go to back by default!
        setTriggerBack(true /* triggerBack */, true /* animated */);
    }
 
    // Let's make sure we only go to the baseextend and apply rubberbanding afterwards
    // 控制绘制和动画的参数赋值
    ... ...
    // By default we just assume the current direction is kept
    boolean triggerBack = mTriggerBack;
 
    //  First lets see if we had continuous motion in one direction for a while
    if (Math.abs(mTotalTouchDelta) > mMinDeltaForSwitch) {
        triggerBack = mTotalTouchDelta > 0;
    }
 
    // 计算方向和偏移值
    // Then, let's see if our velocity tells us to change direction
    mVelocityTracker.computeCurrentVelocity(1000);
    float xVelocity = mVelocityTracker.getXVelocity();
    float yVelocity = mVelocityTracker.getYVelocity();
    float velocity = MathUtils.mag(xVelocity, yVelocity);
    mAngleOffset = Math.min(velocity / 1000 * ARROW_ANGLE_ADDED_PER_1000_SPEED,
            ARROW_MAX_ANGLE_SPEED_OFFSET_DEGREES) * Math.signum(xVelocity);
    if (mIsLeftPanel && mArrowsPointLeft || !mIsLeftPanel && !mArrowsPointLeft) {
        mAngleOffset *= -1;
    }
    // 如果纵向偏移值达到了横向偏移两倍 取消返回事件触发
    // Last if the direction in Y is bigger than X * 2 we also abort
    if (Math.abs(yOffset) > Math.abs(x - mStartX) * 2) {
        triggerBack = false;
    }
    setTriggerBack(triggerBack, true /* animated */);
   ... ...
}

手势处理结果

// NavigationBarEdgePanel.java
    private void triggerBack() {
       // 事件回调到  EdgeBackGestureHandler 进行处理,触发返回事件
        mBackCallback.triggerBack();
 
        // 产生 click 振动
        if (isSlow
                || SystemClock.uptimeMillis() - mVibrationTime >= GESTURE_DURATION_FOR_CLICK_MS) {
            mVibratorHelper.vibrate(VibrationEffect.EFFECT_CLICK);
        }
 
        ...
        // 隐藏动画的执行
        Runnable translationEnd = () -> {
            mAngleOffset = Math.max(0, mAngleOffset + 8);
            updateAngle(true /* animated */);
 
            mTranslationAnimation.setSpring(mTriggerBackSpring);
            setDesiredTranslation(mDesiredTranslation - dp(32), true /* animated */);
            // 隐藏视图
            animate().alpha(0f).setDuration(DISAPPEAR_FADE_ANIMATION_DURATION_MS)
                    .withEndAction(() -> setVisibility(GONE));
            mArrowDisappearAnimation.start();
            scheduleFailsafe();
        };
        ...
    }
    // 取消事件
    private void cancelBack() {
        mBackCallback.cancelBack();
        if (mTranslationAnimation.isRunning()) {
            mTranslationAnimation.addEndListener(mSetGoneEndListener);
        } else {
            setVisibility(GONE);
        }
    }

再看下EdgeBackGestureHandler中的 事件处理:

private final NavigationEdgeBackPlugin.BackCallback mBackCallback =
            new NavigationEdgeBackPlugin.BackCallback() {
                @Override
                public void triggerBack() {
                    sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
                    sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK);
//                    mOverviewProxyService.notifyBackAction(true, (int) mDownPoint.x,
//                            (int) mDownPoint.y, false /* isButton */, !mIsOnLeftEdge);
                    Log.d(TAG, "triggerBack: ");
                }
 
                @Override
                public void cancelBack() {
                    Log.d(TAG, "cancelBack: ");
//                    mOverviewProxyService.notifyBackAction(false, (int) mDownPoint.x,
//                            (int) mDownPoint.y, false  isButton , !mIsOnLeftEdge);
                }
  };
  
  private void sendEvent(int action, int code) {
    long when = SystemClock.uptimeMillis();
    final KeyEvent ev = new KeyEvent(when, when, action, code, 0 /* repeat */,
            0 /* metaState */, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */,
            KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
            InputDevice.SOURCE_KEYBOARD);
    ... ...
    // 用 InputManager 注入返回事件
    InputManager.getInstance().injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}

备注:在PIXEL手机手势设置页面,关闭gesture navigation会回调

 public void onNavigationModeChanged(int mode) {
        mIsGesturalModeEnabled = QuickStepContract.isGesturalMode(mode);
        updateIsEnabled();
        updateCurrentUserResources();
    }

最终会回调解除touch事件监听:

private void disposeInputChannel() {
    if (mInputEventReceiver != null) {
        mInputEventReceiver.dispose();
        mInputEventReceiver = null;
    }
    if (mInputMonitor != null) {
        mInputMonitor.dispose();
        mInputMonitor = null;
    }
}

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐