千里马android framework车机车载手机智能驾驶双屏互动实现方案
背景:
今年车展上,网友蚱蜢同学带回来了一些车载rom相关的一些素材,刚好也发布了wms/ams专题课程,有粉丝朋友提供了一个车机的双屏互动的产品交互视频如下:
上面的就是车机两个屏幕的互动联动情况,转化成设计图如下:
需求说明
这里对在个双屏需求进行要点细分:
1、通过多手指对屏幕1画面A进行拖动滑动
画面A可以跟随手指进行平移,即有跟手功能
拖到一定阈值时候松手,画面A会自动动画移动到屏幕2
拖动和动画过程画面A依旧是可以刷新的,不是截图
在没有达到滑动屏幕2阈值,则需要对画面进行动画返回原来屏幕1的原来位置
上面4个要点就是实现的核心部分,主要难度在以下几个方面:
1、多指全局动作监听,而不是在某个app的onTouch里面监听,这里其实之前的input专题课程是有讲解的
所以这里部分基本上学员都可以搞定
画面A的平移,两个屏幕都要进行显示,这个难度较大,得考虑好相关的画面怎么都可以显示在两个屏幕
画面A移动过程也可以进行刷新,这个相对截图画面A进行显示难度可能又大一些
移动后整个画面A就完全在屏幕2了
需求实现
看完需求,大概也就知道本质就是通过在屏幕1上面多指触摸画面A,然后画面A可以到达屏幕2
那么先不考虑动画体验相关,如果只实现一个最简单版本的双屏移动,哈哈,其实这个车展上也有的车厂就是这样实现的:
这个就是没有动画版本的双屏互动,功能其实也是实现的,但是体验是不是感觉起来差的太多,而且还带有黑屏。。。
不过还好的是功能可以用,那么我们也根据wms课程基础后也来实现一下这个双屏互动的功能。
背景知识-wms的层级结构树
移动的画面A,其实一般就是我们Activity,一般在一个task中
task一般是挂载在某个displaycontent下的TaskDisplayArea下面,具体如下图所示
那么系统中有没有现成的方法就可以吧Task从这个display1移动到对应的diplay2下面呢?
答案当然是有的,方法就是RootWindowContainer里面的
void moveRootTaskToDisplay(int rootTaskId, int displayId, boolean onTop) { final DisplayContent displayContent = getDisplayContentOrCreate(displayId); if (displayContent == null) { throw new IllegalArgumentException("moveRootTaskToDisplay: Unknown displayId=" + displayId); } moveRootTaskToTaskDisplayArea(rootTaskId, displayContent.getDefaultTaskDisplayArea(), onTop); } void moveRootTaskToTaskDisplayArea(int rootTaskId, TaskDisplayArea taskDisplayArea, boolean onTop) { final Task rootTask = getRootTask(rootTaskId); if (rootTask == null) { throw new IllegalArgumentException("moveRootTaskToTaskDisplayArea: Unknown rootTaskId=" + rootTaskId); } final TaskDisplayArea currentTaskDisplayArea = rootTask.getDisplayArea(); if (currentTaskDisplayArea == null) { throw new IllegalStateException("moveRootTaskToTaskDisplayArea: rootTask=" + rootTask + " is not attached to any task display area."); } if (taskDisplayArea == null) { throw new IllegalArgumentException( "moveRootTaskToTaskDisplayArea: Unknown taskDisplayArea=" + taskDisplayArea); } if (currentTaskDisplayArea == taskDisplayArea) { throw new IllegalArgumentException("Trying to move rootTask=" + rootTask + " to its current taskDisplayArea=" + taskDisplayArea); } rootTask.reparent(taskDisplayArea, onTop);//这里就是核心,把task重新挂载到了新display的taskDisplayArea // Resume focusable root task after reparenting to another display area. rootTask.resumeNextFocusAfterReparent(); // TODO(multi-display): resize rootTasks properly if moved from split-screen. }
其实实现也很简单,就是吧task容器重新挂载到新的display的TaskDisplayArea
下面来实际调用一下这个方法的实际效果:
这里其实不需要写代码,可以直接调用am display相关的命令即可以实现这个方法的调用。
可以用am -h看看相关的命令帮助提示,有一个display参数:
display [COMMAND] [...]: sub-commands for operating on displays. move-stack <STACK_ID> <DISPLAY_ID> Move <STACK_ID> from its current display to <DISPLAY_ID>.
使用方式就是:
am display move-stack taskid displayId
那么这里的taskid就是activity所在roottask的id,我们可以通过am stack list看到:
255|emulator_x86_64:/ # am stack listRootTask id=420 bounds=[0,0][1440,2960] displayId=0 userId=0 configuration={1.0 310mcc260mnc [en_US] ldltr sw411dp w411dp h797dp 560dpi nrml long port finger qwerty/v/v dpad/v winConfig={ mBounds=Rect(0, 0 - 1440, 2960) mAppBounds=Rect(0, 0 - 1440, 2876) mMaxBounds=Rect(0, 0 - 1440, 2960) mDisplayRotation=ROTATION_0 mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=standard mAlwaysOnTop=undefined mRotation=ROTATION_0}-455144485 s.24 fontWeightAdjustment=0} taskId=420: com.android.gallery3d/com.android.gallery3d.app.GalleryActivity bounds=[0,0][1440,2960] userId=0 visible=true topActivity=ComponentInfo{com.android.gallery3d/com.android.gallery3d.app.GalleryActivity}RootTask id=1 bounds=[0,0][1440,2960] displayId=0 userId=0 configuration={1.0 310mcc260mnc [en_US] ldltr sw411dp w411dp h797dp 560dpi nrml long port finger qwerty/v/v dpad/v winConfig={ mBounds=Rect(0, 0 - 1440, 2960) mAppBounds=Rect(0, 0 - 1440, 2876) mMaxBounds=Rect(0, 0 - 1440, 2960) mDisplayRotation=ROTATION_0 mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=home mAlwaysOnTop=undefined mRotation=ROTATION_0}-454220964 s.24 fontWeightAdjustment=0} taskId=419: com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher bounds=[0,0][1440,2960] userId=0 visible=false topActivity=ComponentInfo{com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher}RootTask id=3 bounds=[0,0][1440,2960] displayId=0 userId=0 configuration={1.0 310mcc260mnc [en_US] ldltr sw411dp w411dp h797dp 560dpi nrml long port finger qwerty/v/v dpad/v winConfig={ mBounds=Rect(0, 0 - 1440, 2960) mAppBounds=Rect(0, 0 - 1440, 2876) mMaxBounds=Rect(0, 0 - 1440, 2960) mDisplayRotation=ROTATION_0 mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0}-456068006 s.24 fontWeightAdjustment=0} taskId=3: unknown bounds=[0,0][1440,2960] userId=0 visible=falseRootTask id=4 bounds=[0,0][1440,2960] displayId=0 userId=0 configuration={1.0 310mcc260mnc [en_US] ldltr sw411dp w411dp h797dp 560dpi nrml long port finger qwerty/v/v dpad/v winConfig={ mBounds=Rect(0, 0 - 1440, 2960) mAppBounds=Rect(0, 0 - 1440, 2876) mMaxBounds=Rect(0, 0 - 1440, 2960) mDisplayRotation=ROTATION_0 mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0}-456068006 s.24 fontWeightAdjustment=0} taskId=5: unknown bounds=[0,0][1440,2960] userId=0 visible=false taskId=6: unknown bounds=[0,0][1440,2960] userId=0 visible=false
可以看出com.android.gallery3d/com.android.gallery3d.app.GalleryActivity这Activity的对应RootTask id为:
RootTask id=420
dipslayId那就是屏幕的id,这个也可以通过如下命令获取:
test@test:~/Downloads$ adb shell dumpsys display | grep mDisplayIdadb server version (41) doesn't match this client (39); killing...* daemon started successfully mDisplayId=0 mDisplayId=2 mDisplayId=0 mDisplayId=2
一般默认屏幕就是0
所以这里如果要把com.android.gallery3d/com.android.gallery3d.app.GalleryActivity移动到display2命令如下:
am display move-stack 420 2
是不是明显看出来图库从屏幕1转到了屏幕2,屏幕1也有点闪黑
好,那我们下一节再进行具体代码实现,进行手势触摸实现
ps:需要相关代码和资料请加入下面微信公众号哈
来源地址:https://blog.csdn.net/learnframework/article/details/130461689
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341