Android 12源码单手模式
Android 12平台上现在支持单手模式了,此功能也是第一次出现在AOSP的源码中,也是Gg仿 IOS 15 单手模式,来追一追,看看其工作原理。
1.设置应用功能开关界面
com.android.settings.gestures.OneHandedEnablePreferenceController.java
com.android.settings.gestures.OneHandedMainSwitchPreferenceController.java
com.android.settings.gestures.OneHandedSettingsUtils.java
由以上三个文件可以看到:
(1)单手模式的系统开关为:ro.support_one_handed_mode
(2)单手模式显示在系统手势界面
(3)单手模式开关逻辑代码为:
/*** Sets one-handed mode enable or disable flag to Settings provider.** @param context App context* @param enable enable or disable one-handed mode.*/public static void setOneHandedModeEnabled(Context context, boolean enable) {Settings.Secure.putIntForUser(context.getContentResolver(),Settings.Secure.ONE_HANDED_MODE_ENABLED, enable ? ON : OFF, sCurrentUserId);}
2.Launcher3 单手模式手势启动过程
com.android.quickstep.inputconsumers.OneHandedModeInputConsumer.java
com.android.quickstep.SystemUiProxy.java
OneHandedModeInputConsumer类是手势导航处理的类,对于此类的功能描述如下:
* Touch consumer for handling gesture event to launch one handed* One handed gestural in quickstep only active on NO_BUTTON, TWO_BUTTONS, and portrait mode* 触摸消费者处理手势事件以启动单手模式* Quickstep 中的单手手势处理仅在 NO_BUTTON、TWO_BUTTONS 和手机纵向模式下有效。
开启单手模式功能,需要从屏幕底部边缘向下滑动可以开启手势导航,其启动逻辑为:
SystemUiProxy.INSTANCE.get(mContext).startOneHandedMode();public void startOneHandedMode() {if (mOneHanded != null) {try {mOneHanded.startOneHanded();} catch (RemoteException e) {Log.w(TAG, "Failed call startOneHandedMode", e);}}}
3.framework单手模式服务处理过程
(1)单手模式推出进入控制器
com.android.wm.shell.onehanded.IOneHanded.aidl
com.android.wm.shell.onehanded.OneHandedController.java
com.android.wm.shell.onehanded.OneHandedDisplayAreaOrganizer.java
com.android.wm.shell.onehanded.OneHandedAnimationController.java
com.android.wm.shell.onehanded.OneHandedTouchHandler.java
com.android.wm.shell.onehanded.OneHandedSurfaceTransactionHelper.java
@VisibleForTestingvoid startOneHanded() {if (isLockedDisabled() || mKeyguardShowing) {Slog.d(TAG, "Temporary lock disabled");return;}if (!mDisplayAreaOrganizer.isReady()) {// Must wait until DisplayAreaOrganizer is ready for transitioning.mMainExecutor.executeDelayed(this::startOneHanded, DISPLAY_AREA_READY_RETRY_MS);return;}if (mState.isTransitioning() || mState.isInOneHanded()) {return;}final int currentRotation = mDisplayAreaOrganizer.getDisplayLayout().rotation();if (currentRotation != Surface.ROTATION_0 && currentRotation != Surface.ROTATION_180) {Slog.w(TAG, "One handed mode only support portrait mode");return;}mState.setState(STATE_ENTERING);final int yOffSet = Math.round(mDisplayAreaOrganizer.getDisplayLayout().height() * mOffSetFraction);mOneHandedAccessibilityUtil.announcementForScreenReader(mOneHandedAccessibilityUtil.getOneHandedStartDescription());mBackgroundPanelOrganizer.onStart();mDisplayAreaOrganizer.scheduleOffset(0, yOffSet);mTimeoutHandler.resetTimer();mOneHandedUiEventLogger.writeEvent(OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_GESTURE_IN);}
由以上可以看到,设备锁定/锁屏/横屏是不允许进入单手模式的。进入单手模式时屏幕会有Y轴方向的偏移,偏移百分比为mOffSetFraction,mOffSetFraction的值获取是从 R.fraction.config_one_handed_offset获取的:
frameworks/base/libs/WindowManager/Shell/res/values/config.xml
<fraction name="config_one_handed_offset">40%</fraction>
接着上面说,单手模式会对的显示做偏移:
/*** Offset the windows by a given offset on Y-axis, triggered also from screen rotation.* Directly perform manipulation/offset on the leash.*/public void scheduleOffset(int xOffset, int yOffset) {final float fromPos = mLastVisualOffset;final int direction = yOffset > 0? TRANSITION_DIRECTION_TRIGGER: TRANSITION_DIRECTION_EXIT;mDisplayAreaTokenMap.forEach((token, leash) -> {animateWindows(token, leash, fromPos, yOffset, direction,mEnterExitAnimationDurationMs);});mLastVisualOffset = yOffset;}private void animateWindows(WindowContainerToken token, SurfaceControl leash, float fromPos,float toPos, @OneHandedAnimationController.TransitionDirection int direction,int durationMs) {final OneHandedAnimationController.OneHandedTransitionAnimator animator =mAnimationController.getAnimator(token, leash, fromPos, toPos,mLastVisualDisplayBounds);if (animator != null) {animator.setTransitionDirection(direction).addOneHandedAnimationCallback(mOneHandedAnimationCallback).addOneHandedAnimationCallback(mTutorialHandler).addOneHandedAnimationCallback(mBackgroundPanelOrganizer).setDuration(durationMs).start();}}
OneHandedAnimationController处理过程中会有动画处理,而主要针对SurfaceControl做处理:
@Overridevoid applySurfaceControlTransaction(SurfaceControl leash,SurfaceControl.Transaction tx, float fraction) {final float start = getStartValue();final float end = getEndValue();final float currentValue = getCastedFractionValue(start, end, fraction);mTmpRect.set(mTmpRect.left,mTmpRect.top + Math.round(currentValue),mTmpRect.right,mTmpRect.bottom + Math.round(currentValue));setCurrentValue(currentValue);getSurfaceTransactionHelper().crop(tx, leash, mTmpRect).round(tx, leash).translate(tx, leash, currentValue);tx.apply();}
getSurfaceTransactionHelper返回的是OneHandedSurfaceTransactionHelper,其整合了一些对SurfaceControl的方法:
/*** Operates the translation (setPosition) on a given transaction and leash** @return same {@link OneHandedSurfaceTransactionHelper} instance for method chaining*/OneHandedSurfaceTransactionHelper translate(SurfaceControl.Transaction tx, SurfaceControl leash,float offset) {tx.setPosition(leash, 0, offset);return this;}/*** Operates the crop (setMatrix) on a given transaction and leash** @return same {@link OneHandedSurfaceTransactionHelper} instance for method chaining*/OneHandedSurfaceTransactionHelper crop(SurfaceControl.Transaction tx, SurfaceControl leash,Rect destinationBounds) {tx.setWindowCrop(leash, destinationBounds.width(), destinationBounds.height());return this;}/*** Operates the round corner radius on a given transaction and leash** @return same {@link OneHandedSurfaceTransactionHelper} instance for method chaining*/OneHandedSurfaceTransactionHelper round(SurfaceControl.Transaction tx, SurfaceControl leash) {if (mEnableCornerRadius) {tx.setCornerRadius(leash, mCornerRadius);}return this;}
setWindowCrop设置裁切大小,setCornerRadius设置圆角,setPosition设置位置。
(2)单手模式触摸事件管理
com.android.wm.shell.onehanded.OneHandedTouchHandler
当触摸非应用界面的位置时,回调OneHandedController.stopOneHanded,推出单手模式:
private boolean onMotionEvent(MotionEvent ev) {mIsInOutsideRegion = isWithinTouchOutsideRegion(ev.getX(), ev.getY());switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:case MotionEvent.ACTION_MOVE: {if (!mIsInOutsideRegion) {mTimeoutHandler.resetTimer();}break;}case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL: {mTimeoutHandler.resetTimer();if (mIsInOutsideRegion && !mIsOnStopTransitioning) {mTouchEventCallback.onStop();mIsOnStopTransitioning = true;}// Reset flag for next operationmIsInOutsideRegion = false;break;}}return true;}
Android 12源码单手模式相关推荐
- android 12 源码编译与虚拟机调试
android 12 源码编译与虚拟机调试 android 12编译环境搭建 安装android 12环境依赖 android 12源码下载 下载repo工具 repo工具下载 国内repo工具修改 ...
- Android 12源码编译报错:FAILED: out/soong/build.ninja
Android 12源码编译报错:FAILED: out/soong/build.ninja android12源码编译中报如下错误: 网上查了比较多资料发现是swap分区不够导致的,报错时使用fre ...
- Android 11源码 Framework修改默认usb连接模式为MTP模式
Android 11源码 Framework修改默认usb连接模式为MTP模式 Android 11源码 Framework修改默认usb连接模式为MTP模式 修改Framework层源码 编译修改后 ...
- 【Android SDM660源码分析】- 02 - UEFI XBL QcomChargerApp充电流程代码分析
[Android SDM660源码分析]- 02 - UEFI XBL QcomChargerApp充电流程代码分析 一.加载 UEFI 默认应用程序 1.1 LaunchDefaultBDSApps ...
- android系统源码中添加app源码(源码部署移植)
涉及到系统定制,需要在系统中加入自己的apk工程,但是上网找了很多资料都是不够全面的,或者看了还是没搞懂,我自己也是一点点摸索过来的,花了不少的时间,也是踩了不少的坑,因此特开一文,帮助大家渡河. 申 ...
- [Android精品源码] Android 仿美团网,探索ListView的A-Z字母排序功能实现选择城市
Material Design中文版Code4APPPHP100UI4APP 开启辅助访问设为首页收藏本站快捷导航切换到宽版切换风格 石刚 | |我的 |签到打卡 |设置 |消息 |提醒(2) |退出 ...
- Android系统源码
作者:王宇龙 链接:https://www.zhihu.com/question/19759722/answer/29213925 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非商业转载 ...
- 大牛们是怎么阅读 Android 系统源码的?
转载自https://www.zhihu.com/question/19759722 作者:王宇龙 链接:https://www.zhihu.com/question/19759722/answer/ ...
- 173个Android项目源码及下载地址
173个Android项目源码及下载地址 注:最近一直没有上CSDN,看到不少想学Android的朋友们想要这几个Android项目源码,所以我把它上传到了CSDN,希望能在Android的学习路上对 ...
最新文章
- jquery 1.6以上版本 全选
- ACMNO.2 输入一个华氏温度,要求输出摄氏温度。公式为 c=5(F-32)/9 输出要求有文字说明,取位2小数。 输入 一个华氏温度,浮点数 输出 摄氏温度,浮点两位小数
- 国外17个非常热门的在线备份服务
- gcc编译器与g++编译器的区别
- JSTL fmt 标签 使用
- html请求接口_Python 如何使用 HttpRunner 做接口自动化测试
- 工具教程第十一讲:如何加入电报群
- Available platform plugins are: xcb, eglfs, linuxfb, minimal, minimalegl, of
- css:flex布局子元素宽度被压缩问题
- 非标准分布随机数生成 - 逆变换ITM与舍选法Rejection
- umi中@umijs/plugin-dva的使用,及实现一套增删改
- 12步解N-S方程之第三步
- 卷积神经网络处理一维信号(故障诊断)
- C语言电话号码判断合法性
- 好书精读推荐:《苏世民:我的经验与教训》
- RabbitMQ:什么是消息队列MQ?为什么使用消息队列MQ?入门MQ先学哪种?(一)
- 发牌 胡俊杰买到库洛牌后,要将库洛牌分发给小伙伴们。
- 去除字符串中特殊表情--正则
- Python实现换脸
- 一篇文章带你搞定数学建模中的载荷矩阵、相关系数矩阵、主成分分析(11年土壤重金属污染示例讲解含代码)