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系统导航栏视图分析》

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

手势导航功能的实现主要由 SystemUI + Launcher3 共同处理,SystemUI 中主要由 OverviewProxyService.java 监听,而在 Launcher3 中启动一个 TouchInteractionService 服务监听,主要代码实现都由 Launcher 中处理。

Launcher3/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.javaprivate void initInputMonitor() {disposeEventHandlers();if (mDeviceState.isButtonNavMode() || !SystemUiProxy.INSTANCE.get(this).isActive()) {return;}Bundle bundle = SystemUiProxy.INSTANCE.get(this).monitorGestureInput("swipe-up",mDeviceState.getDisplayId());mInputMonitorCompat = InputMonitorCompat.fromBundle(bundle, KEY_EXTRA_INPUT_MONITOR);//注册处理 view input 事件,在 onInputEvent 中进行处理mInputEventReceiver = mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(),mMainChoreographer, this::onInputEvent);mDeviceState.updateGestureTouchRegions();}... ...private void onInputEvent(InputEvent ev) {... ...final int action = event.getAction();if (action == ACTION_DOWN) {... ...// 判断是手势底部向上滑动if (mDeviceState.isInSwipeUpTouchRegion(event)) {... ...GestureState prevGestureState = new GestureState(mGestureState);GestureState newGestureState = createGestureState(mGestureState);mConsumer.onConsumerAboutToBeSwitched();mGestureState = newGestureState;// 根据当前实际情况创建不同的 InputConsumermConsumer = newConsumer(prevGestureState, mGestureState, event);mUncheckedConsumer = mConsumer;... ...} else {// 其他 MOVE UP CANCEL 事件处理if (mUncheckedConsumer != InputConsumer.NO_OP) {// 处理滑动动画效果mDeviceState.setOrientationTransformIfNeeded(event);}}boolean cleanUpConsumer = (action == ACTION_UP || action == ACTION_CANCEL)&& mConsumer != null&& !mConsumer.getActiveConsumerInHierarchy().isConsumerDetachedFromGesture();// 交由具体的 InputConsumer 去继续处理mUncheckedConsumer.onMotionEvent(event);// 结束 reset 状态if (cleanUpConsumer) {reset();}}

TouchInteractionService 是 Launcher 中开始地方,initInputMonitor() 函数中注册 onInputEvent 事件监听。这个 onInputEvent 从 BatchedInputEventReceiver(继承 InputEventReceiver.java) 的 onInputEvent 调用。

onInputEvent 函数中处理滑动事件,在 DOWN 事件时根据不同的场景创建不同的 InputConsumer,例如在桌面、或其他界面等不同情况下使用手势,对应的 InputConsumer 是不同的,最常见的就是 OtherActivityInputConsumer (其他Activity界面使用手势导航)。

Launcher3/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.javapublic void onMotionEvent(MotionEvent ev) {switch (ev.getActionMasked()) {case ACTION_DOWN: {// 非关键代码break;}case ACTION_MOVE: {int pointerIndex = ev.findPointerIndex(mActivePointerId);if (pointerIndex == INVALID_POINTER_ID) {break;}mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));float displacement = getDisplacement(ev);float displacementX = mLastPos.x - mDownPos.x;float displacementY = mLastPos.y - mDownPos.y;if (!mPassedWindowMoveSlop) {if (!mIsDeferredDownTarget) {// Normal gesture, ensure we pass the drag slop before we start tracking// the gestureif (Math.abs(displacement) > mTouchSlop) {mPassedWindowMoveSlop = true;mStartDisplacement = Math.min(displacement, -mTouchSlop);}}}float horizontalDist = Math.abs(displacementX);float upDist = -displacement;boolean passedSlop = squaredHypot(displacementX, displacementY)>= mSquaredTouchSlop;if (!mPassedSlopOnThisGesture && passedSlop) {mPassedSlopOnThisGesture = true;}// Until passing slop, we don't know what direction we're going, so assume// we're quick switching to avoid translating recents away when continuing// the gesture (in which case mPassedPilferInputSlop starts as true).boolean haveNotPassedSlopOnContinuedGesture =!mPassedSlopOnThisGesture && mPassedPilferInputSlop;boolean isLikelyToStartNewTask = haveNotPassedSlopOnContinuedGesture|| horizontalDist > upDist;if (!mPassedPilferInputSlop) {if (passedSlop) {if (mDisableHorizontalSwipe&& Math.abs(displacementX) > Math.abs(displacementY)) {// Horizontal gesture is not allowed in this regionforceCancelGesture(ev);break;}mPassedPilferInputSlop = true;if (mIsDeferredDownTarget) {// 启动动画startTouchTrackingForWindowAnimation(ev.getEventTime());}if (!mPassedWindowMoveSlop) {mPassedWindowMoveSlop = true;mStartDisplacement = Math.min(displacement, -mTouchSlop);}// 通知开始手势滑动notifyGestureStarted(isLikelyToStartNewTask);}}if (mInteractionHandler != null) {if (mPassedWindowMoveSlop) {// 更新移动位置mInteractionHandler.updateDisplacement(displacement - mStartDisplacement);}// 更新移动检测if (mDeviceState.isFullyGesturalNavMode()) {mMotionPauseDetector.setDisallowPause(upDist < mMotionPauseMinDisplacement|| isLikelyToStartNewTask);mMotionPauseDetector.addPosition(ev);mInteractionHandler.setIsLikelyToStartNewTask(isLikelyToStartNewTask);}}break;}case ACTION_CANCEL:case ACTION_UP: {if (DEBUG_FAILED_QUICKSWITCH && !mPassedWindowMoveSlop) {float displacementX = mLastPos.x - mDownPos.x;float displacementY = mLastPos.y - mDownPos.y;Log.d("Quickswitch", "mPassedWindowMoveSlop=false"+ " disp=" + squaredHypot(displacementX, displacementY)+ " slop=" + mSquaredTouchSlop);}finishTouchTracking(ev);break;}}}

OtherActivityInputConsumer 是具体处理的类。主要都在 onMotionEvent ACTION_MOVE 事件做处理。

startTouchTrackingForWindowAnimation 函数中进行 mInteractionHandler 等初始化操作及设置动画开始。

notifyGestureStarted 函数中设置开始手势滑动状态。

接下来的 if (mInteractionHandler != null) 代码块中就是具体滑动时候的动画缩放显示等操作。

finishTouchTracking(ev) 函数中通知滑动结束,通知最终状态。

private void finishTouchTracking(MotionEvent ev) {... ...if (mPassedWindowMoveSlop && mInteractionHandler != null) {if (ev.getActionMasked() == ACTION_CANCEL) {// 手势滑动取消mInteractionHandler.onGestureCancelled();} else {// 手势滑动正常结束mVelocityTracker.computeCurrentVelocity(1000,ViewConfiguration.get(this).getScaledMaximumFlingVelocity());float velocityX = mVelocityTracker.getXVelocity(mActivePointerId);float velocityY = mVelocityTracker.getYVelocity(mActivePointerId);float velocity = mNavBarPosition.isRightEdge()? velocityX: mNavBarPosition.isLeftEdge()? -velocityX: velocityY;// up 动作时最后修改一次位置mInteractionHandler.updateDisplacement(getDisplacement(ev) - mStartDisplacement);// 通知滑动结束mInteractionHandler.onGestureEnded(velocity, new PointF(velocityX, velocityY),mDownPos);}}... ...}

判断最终是执行的 HOMO 还是 RECENTS 等事件是在 mInteractionHandler (BaseSwipeUpHandlerV2.java) 中根据滑动中的数据具体判断。

Launcher3/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.javapublic void onGestureEnded(float endVelocity, PointF velocity, PointF downPos) {float flingThreshold = mContext.getResources().getDimension(R.dimen.quickstep_fling_threshold_velocity);boolean isFling = mGestureStarted && Math.abs(endVelocity) > flingThreshold;mStateCallback.setStateOnUiThread(STATE_GESTURE_COMPLETED);mLogAction = isFling ? Touch.FLING : Touch.SWIPE;boolean isVelocityVertical = Math.abs(velocity.y) > Math.abs(velocity.x);if (isVelocityVertical) {mLogDirection = velocity.y < 0 ? Direction.UP : Direction.DOWN;} else {mLogDirection = velocity.x < 0 ? Direction.LEFT : Direction.RIGHT;}mDownPos = downPos;handleNormalGestureEnd(endVelocity, isFling, velocity, false /* isCancel */);}private void handleNormalGestureEnd(float endVelocity, boolean isFling, PointF velocity,boolean isCancel) {PointF velocityPxPerMs = new PointF(velocity.x / 1000, velocity.y / 1000);long duration = MAX_SWIPE_DURATION;float currentShift = mCurrentShift.value;// 根据滑动数值判断最终是什么类型事件final GestureEndTarget endTarget = calculateEndTarget(velocity, endVelocity,isFling, isCancel);float endShift = endTarget.isLauncher ? 1 : 0;final float startShift;Interpolator interpolator = DEACCEL;if (!isFling) {long expectedDuration = Math.abs(Math.round((endShift - currentShift)* MAX_SWIPE_DURATION * SWIPE_DURATION_MULTIPLIER));duration = Math.min(MAX_SWIPE_DURATION, expectedDuration);startShift = currentShift;interpolator = endTarget == RECENTS ? OVERSHOOT_1_2 : DEACCEL;} else {startShift = Utilities.boundToRange(currentShift - velocityPxPerMs.y* getSingleFrameMs(mContext) / mTransitionDragLength, 0, mDragLengthFactor);float minFlingVelocity = mContext.getResources().getDimension(R.dimen.quickstep_fling_min_velocity);if (Math.abs(endVelocity) > minFlingVelocity && mTransitionDragLength > 0) {if (endTarget == RECENTS && !mDeviceState.isFullyGesturalNavMode()) {Interpolators.OvershootParams overshoot = new Interpolators.OvershootParams(startShift, endShift, endShift, endVelocity / 1000,mTransitionDragLength, mContext);endShift = overshoot.end;interpolator = overshoot.interpolator;duration = Utilities.boundToRange(overshoot.duration, MIN_OVERSHOOT_DURATION,MAX_SWIPE_DURATION);} else {float distanceToTravel = (endShift - currentShift) * mTransitionDragLength;// we want the page's snap velocity to approximately match the velocity at// which the user flings, so we scale the duration by a value near to the// derivative of the scroll interpolator at zero, ie. 2.long baseDuration = Math.round(Math.abs(distanceToTravel / velocityPxPerMs.y));duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration);if (endTarget == RECENTS) {interpolator = OVERSHOOT_1_2;}}}}if (endTarget.isLauncher && mRecentsAnimationController != null) {mRecentsAnimationController.enableInputProxy(mInputConsumer,this::createNewInputProxyHandler);}if (endTarget == HOME) {setShelfState(ShelfAnimState.CANCEL, LINEAR, 0);duration = Math.max(MIN_OVERSHOOT_DURATION, duration);} else if (endTarget == RECENTS) {LiveTileOverlay.INSTANCE.startIconAnimation();if (mRecentsView != null) {int nearestPage = mRecentsView.getPageNearestToCenterOfScreen();if (mRecentsView.getNextPage() != nearestPage) {// We shouldn't really scroll to the next page when swiping up to recents.// Only allow settling on the next page if it's nearest to the center.mRecentsView.snapToPage(nearestPage, Math.toIntExact(duration));}if (mRecentsView.getScroller().getDuration() > MAX_SWIPE_DURATION) {mRecentsView.snapToPage(mRecentsView.getNextPage(), (int) MAX_SWIPE_DURATION);}duration = Math.max(duration, mRecentsView.getScroller().getDuration());}if (mDeviceState.isFullyGesturalNavMode()) {setShelfState(ShelfAnimState.OVERVIEW, interpolator, duration);}}// Let RecentsView handle the scrolling to the task, which we launch in startNewTask()// or resumeLastTask().if (mRecentsView != null) {mRecentsView.setOnPageTransitionEndCallback(() -> mGestureState.setState(STATE_RECENTS_SCROLLING_FINISHED));} else {mGestureState.setState(STATE_RECENTS_SCROLLING_FINISHED);}animateToProgress(startShift, endShift, duration, interpolator, endTarget, velocityPxPerMs);}

最终以 handleNormalGestureEnd 结束,这里 calculateEndTarget 进行判断最终的手势滑动动作是哪种。

系统设置有四种手势动作:

1,HOME 回到主界面

2,RECENTS 多任务界面

3,NEW_TASK 切换到新的应用

4,LAST_TASK 仍然停留在当前界面

手势动作,从底部往上滑,启动RECENTS 多任务界面

动画效果会让背景页面可见,回到luncher3页面,加载QuickstepLauncher,其中LauncherRecentsView加载应用的容器。

Android 手势导航(从下往上滑动进入多任务页面)相关推荐

  1. Android从上往下滑动或从下往上滑动结束Activity

    之前有看过xiaanming写的侧滑返回,于是仿照他的Demo,写了这个从上往下滑动或者从下往上滑动结束Activity 先附图一张,由于这台电脑分辨率有问题以及模拟器的缘故,先凑活看吧 先贴代码: ...

  2. android studio 顶部导航栏_Android10 手势导航开发与处理:边到边(I)

    这是我们有关"手势导航"系列的第一篇文章. 借助Android 10,已添加了新的系统导航模式,允许用户向后导航,导航至主屏幕并通过手势触发设备助手. Android 10 中新手 ...

  3. recyclerview 滚动冲突_如何处理手势冲突 | 手势导航连载 (三)

    作者 / Chris Banes, Android 开发者关系团队工程师 我们将在近期为大家带来一个关于 "手势导航" 的系列连载,本文是手势导航连载的第三篇,如果您希望查看前两篇 ...

  4. android 虚拟导航按钮(NavigationBar)可手动隐藏开发

    NavigationBar可以手动隐藏,随着华为荣耀手机有了这个特点后,目前有很多android手机都有该特性.如下截图所示: 上图的底部虚拟导航按钮的左.右边有两个按钮点击这个按钮,虚拟按钮就会消失 ...

  5. 开启全面屏体验 | 手势导航 (一)

    作者 / Chris Banes, Android 开发者关系团队工程师 本文是手势导航连载的第一篇文章,在接下来的时间里,我们将会为大家带来一系列手势导航的话题,敬请关注! 我们在 Android ...

  6. 如何在任何Android手机上获取手势导航

    Android's upcoming iteration (currently just called "P") contains a new gesture navigation ...

  7. 【Android 手势冲突】Colin带你彻底解决RecyclerView与ScrollView滑动冲突问题,并实现RecyclerView悬停导航栏(附demo哦)

    在新一期的需求中,产品要求我们做出和美团某个页面类似的功能,即一个页面包含在scrollView中,上面一个部分放置一些常用的广告banner.宫格tab等,下面放置一个RecyclerView用于展 ...

  8. Android 11.0 自定义仿小米全面屏手势导航左右手势滑动返回UI效果

    目录 1.概述 2.自定义仿小米全面屏手势导航返回ui布局的核心代码 3.自定义左右手势返回UI样式的核心代码功能分析 3.1 NavigationBarView手势导航布局左右手势返回的相关代码 3 ...

  9. Android 12.0 自定义仿小米全面屏手势导航左右手势滑动返回UI效果

    目录 1.概述 2.自定义仿小米全面屏手势导航左右手势滑动返回UI效果的核心类

最新文章

  1. (转)linux运行tomcat时JRE_HOME显示不对怎么办?
  2. Activity动态增加Fragment
  3. i219 2012驱动_2012年I / O之后
  4. c 语言str.size,C/C++ strlen(str)和str.length()和str.size()的区别
  5. db2数据库还原找不到文件_db2数据库还原
  6. log4j记录不同的日志_Spring boot中使用log4j记录日志
  7. 使用sklearn进行数据挖掘
  8. ROS采坑日记(3)----在ROS下 编译ORB_SLAM2时遇到问题:[rosbuild] rospack found package ORB_SLAM2 at ........
  9. leetcode刷题日记- 重复叠加字符串匹配
  10. Atitit.404错误解决标准流程and url汉字中文路径404错误resin4 resin chinese char path 404 err解决
  11. Iframe的基础应用——关于Iframe刷页问题的两种方法
  12. java的维护_天了噜,Java 8 要停止维护了!
  13. 视频教程-华为HCNA网络工程师【从入门到精通】自学视频[肖哥]-华为认证
  14. HR人事管理系统软件有哪些?如何选择HR人事管理软件?
  15. linux 开启bat文件夹,在Linux系统中使用及定制Bat
  16. 基于Javaweb校园代步工具租赁系统毕业设计源码061335
  17. java put 语句_Java put语句
  18. C++:实现将华氏度转换为摄氏度
  19. 平台建设的7大问题:蚂蚁AI平台实践深度总结
  20. 【综合算法】不考虑误差的TDOA定位

热门文章

  1. SSM系类代码:java.io.UnsupportedEncodingException
  2. 本地项目上传公司GitLab步骤
  3. 手机的命名Note、Mate、MIX、Pro……都代表什么意思?
  4. 如何在一个html页面使用多个kindeditor编辑器
  5. 3.29 校招实习发布
  6. CSS页面布局之盒子模型
  7. 16届亚洲运动会(广州亚运会)的官网的URL和js都挺逗
  8. Android中 ComponentName 组件的使用
  9. 春秋云镜 CVE-2022-24223
  10. H5时钟的完整版(粘贴复制直接看效果)