framework直播学习笔记--安卓如何实现Launcher启动应用全部变自由窗口Freeform模式

背景:

前些天在学员在学员群里有聊到一个需求,那就是把手机桌面点击应用图标后,不是进行全屏显示,而是都进行自由窗口显示。这个其实有点类似我们windows电脑打开app,每个app都是一个非全屏的窗口,而且可以同时显示很多app的窗口。而不是一直被一个app的全屏窗口覆盖。如下图所示:
在这里插入图片描述
这个需求如何实现呢?那么接下来就来详细实现一下。

实现过程:

先看看B站UP主“千里马学框架”直播笔记:
在这里插入图片描述
实现Launcher端启动App都变成自由窗口模式非全屏模式

核心思路:

这个windowmode需要从FullScreen —> Freeform ,需要在startActivity时候携带相关相关参数,把windowmode和launchBounds进行设置。

步骤如下:

1、寻找到相关的桌面点击App的startActivity的相关方法,考虑对这个方法进行修改参数

2、对startActivity时候携带的ActivityOptions参数进行添加相关windowmode,launcherbounds的设置

launcher启动App的方法堆栈

假设你是一个桌面小白,根本不知道桌面的具体业务代码,请问你有什么方法可以快速定位出桌面是在哪个代码中startActivity吗?
方案1:
硬看代码,这里就需要自己先了解launcher的app图标代码,去寻找app的图标点击onClick方法,一步步寻找
缺点:现在的launcher代码已经变得很复杂,封装很多,基本上直接看代码很难找到对应onClick方法,因为层次很深,而且onClick方法可能还是lamada表达式等,大大增加了寻找难度。
方案2:
打印堆栈方法或者调试,首先有了马哥framework课程的基础后,大家都知道Activity的启动最后都会调用的Instrumentation的execStartActivity方法中

在这里插入图片描述
所以完全可以这里加入Instrumentation加入相关的堆栈或者调试寻找到onClick和startActivity方法

getService:156, ActivityTaskManager (android.app)
execStartActivity:1873, Instrumentation (android.app)
startActivityForResult:5589, Activity (android.app)
startActivityForResult:1834, Launcher (com.android.launcher3)
startActivityForResult:845, QuickstepLauncher (com.android.launcher3.uioverrides)
startActivity:6041, Activity (android.app)
startActivitySafely:379, ActivityContext (com.android.launcher3.views)
startActivitySafely:2196, Launcher (com.android.launcher3)
startActivitySafely:350, QuickstepLauncher (com.android.launcher3.uioverrides)
startAppShortcutOrInfoActivity:351, ItemClickHandler (com.android.launcher3.touch)
onClickAppShortcut:309, ItemClickHandler (com.android.launcher3.touch)
onClick:94, ItemClickHandler (com.android.launcher3.touch)
$r8$lambda$c3IcSovkrXGdCZtXy0f_A5Sz5VA:-1, ItemClickHandler (com.android.launcher3.touch)
onClick:-1, ItemClickHandler$$ExternalSyntheticLambda6 (com.android.launcher3.touch)
onItemClicked:388, QuickstepLauncher (com.android.launcher3.uioverrides)
onClick:-1, QuickstepLauncher$$ExternalSyntheticLambda11 (com.android.launcher3.uioverrides)
performClick:7659, View (android.view)
performClickInternal:7636, View (android.view)
-$$Nest$mperformClickInternal:-1, View (android.view)
run:30156, View$PerformClick (android.view)
handleCallback:958, Handler (android.os)
dispatchMessage:99, Handler (android.os)
loopOnce:205, Looper (android.os)
loop:294, Looper (android.os)
main:8177, ActivityThread (android.app)
invoke:-1, Method (java.lang.reflect)
run:552, RuntimeInit$MethodAndArgsCaller (com.android.internal.os)
main:971, ZygoteInit (com.android.internal.os)

看一下堆栈是不是很清晰整个startActivity的过程,清楚知道在哪里启动的onClick且一步步到对应的startActivity,这里寻找最贴近context的startActivity,那就是

startActivitySafely:379, ActivityContext (com.android.launcher3.views)

在这里插入图片描述
好到了这里就算寻找到添加的地方

添加相关参数并修复bug:

添加相关的修改部分

default RunnableList startActivitySafely(
            View v, Intent intent, @Nullable ItemInfo item) {
//省略
        ActivityOptionsWrapper options = v != null ? getActivityLaunchOptions(v, item)
                : makeDefaultActivityOptions(item != null && item.animationType == DEFAULT_NO_ICON
                        ? SPLASH_SCREEN_STYLE_SOLID_COLOR : -1 /* SPLASH_SCREEN_STYLE_UNDEFINED */);
        UserHandle user = item == null ? null : item.user;
        Bundle optsBundle = options.toBundle();
        //省略
            if (isShortcut) {
                // Shortcuts need some special checks due to legacy reasons.
                startShortcutIntentSafely(intent, optsBundle, item);
            } else if (user == null || user.equals(Process.myUserHandle())) {
               //开始在原来启动options基础添加相关的WindowingMode和LaunchBounds
                options.options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
                final Rect r = new Rect(0, 0, 1440, (int)(2960 * 0.63f));
                options.options.setLaunchBounds(r);
                //添加结束后需要重新转换成toBundle
                optsBundle = options.toBundle();
                // Could be launching some bookkeeping activity
                context.startActivity(intent, optsBundle);
            } 

上面修改已经有详细注释了,看看添加后的效果:
在这里插入图片描述
看到确实是可以启动Freeform模式的App,不过好像窗口的坐标不是我们设置的,一直显示在左上角,而且状态栏还遮盖了,导致无法拖拉自由窗口,那么到底啥原因导致该问题呢?
这里其实以前学习马哥分屏自由窗口专题时候就有发现类似问题,马哥也带大家手把手解决了,现在依然用老方法打堆栈定位啥原因:

在这里插入图片描述追查到了其实是因为远程动画也有对坐标进行再次设置成0,所以一直左上角,那么是否可以考虑去除桌面启动app远程动画呢?具体桌面去除呢?具体如下:

					//最重要不在复用原启动ActivityOptions
                ActivityOptions activityOptions = ActivityOptions.makeBasic();
                activityOptions.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
                final Rect r = new Rect(0, 0, 1440, (int)(2960 * 0.63f));
                activityOptions.setLaunchBounds(r);
                // Could be launching some bookkeeping activity
                context.startActivity(intent, activityOptions.toBundle());//最重要不在复用原启动ActivityOptions

上面最重要就是不在复用原桌面启动ActivityOptions,自己全新定义ActivityOptions,只有setLaunchWindowingMode和setLaunchBounds,然后startActivity就只带这个ActivityOptions。

最后的完美效果如下:
在这里插入图片描述

具体详情试看方式:
投屏专题部分:
https://mp.weixin.qq.com/s/IGm6VHMiAOPejC_H3N_SNg

更多framework详细代码和资料参考如下链接

hal+perfetto+surfaceflinger
https://mp.weixin.qq.com/s/LbVLnu1udqExHVKxd74ILg
在这里插入图片描述

其他课程七件套专题:在这里插入图片描述
点击这里
https://mp.weixin.qq.com/s/Qv8zjgQ0CkalKmvi8tMGaw

视频试看:
https://www.bilibili.com/video/BV1wc41117L4/

更多framework假威风耗:androidframework007

  • 16
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值