车机CarLauncher的Activity多屏模式WindowingMode为WINDOWING_MODE_MULTI_WINDOW疑问解析

这篇具有很好参考价值的文章主要介绍了车机CarLauncher的Activity多屏模式WindowingMode为WINDOWING_MODE_MULTI_WINDOW疑问解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

hi,粉丝朋友们!

   @IntDef(prefix = { "WINDOWING_MODE_" }, value = {
            WINDOWING_MODE_UNDEFINED,
            WINDOWING_MODE_FULLSCREEN,
            WINDOWING_MODE_MULTI_WINDOW,
            WINDOWING_MODE_PINNED,
            WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
            WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
            WINDOWING_MODE_FREEFORM,
    })

今天来给大家介绍一下再Activity中WindowMode相关的多窗口模式,这个模式相对平时比较少见,但是在分屏模式之自由窗口模式,等存在多个窗口场景就很关键了。这一部分确实不是普通模式的场景,而且每一种模式都是比较难的,今天来分析一下WINDOWING_MODE_MULTI_WINDOW模式的一个疑问。

疑问背景:

activity的WindowMode被设置成了WINDOWING_MODE_MULTI_WINDOW后,或者其他几个非WINDOWING_MODE_FULLSCREEN的WindowMode,为啥可以同一个画面显示多个Activity,而且多个Activity都是Resume的状态。
比如拿我们CarLauncher的地图画面来说:
车机CarLauncher的Activity多屏模式WindowingMode为WINDOWING_MODE_MULTI_WINDOW疑问解析

具体可以看对应的am stack list看看Task和Activity相关的情况

test@test:~$ adb shell am stack list
RootTask id=1000098 bounds=[303,57][1200,658] displayId=0 userId=10
 configuration={1.0 310mcc260mnc [en_US] ldltr sw1066dp w1196dp h801dp 120dpi xlrg land car finger qwerty/v/v -nav/h winConfig={ mBounds=Rect(303, 57 - 1200, 658) mAppBounds=Rect(303, 57 - 1200, 658) mMaxBounds=Rect(0, 0 - 1200, 800) mDisplayRotation=ROTATION_0 mWindowingMode=multi-window mDisplayWindowingMode=fullscreen mActivityType=standard mAlwaysOnTop=undefined mRotation=ROTATION_0} as.2 s.29 fontWeightAdjustment=0}
  taskId=1000098: com.android.car.mapsplaceholder/com.android.car.mapsplaceholder.MapsPlaceholderActivity bounds=[303,57][1200,658] userId=10 visible=true topActivity=ComponentInfo{com.android.car.mapsplaceholder/com.android.car.mapsplaceholder.MapsPlaceholderActivity}

RootTask id=1 bounds=[0,0][1200,800] displayId=0 userId=10
 configuration={1.0 310mcc260mnc [en_US] ldltr sw1066dp w1600dp h1042dp 120dpi xlrg land car finger qwerty/v/v -nav/h winConfig={ mBounds=Rect(0, 0 - 1200, 800) mAppBounds=Rect(0, 0 - 1200, 800) mMaxBounds=Rect(0, 0 - 1200, 800) mDisplayRotation=ROTATION_0 mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=home mAlwaysOnTop=undefined mRotation=ROTATION_0} as.2 s.29 fontWeightAdjustment=0}
  taskId=2: com.android.car.settings/com.android.car.settings.FallbackHome bounds=[0,0][1200,800] userId=0 visible=true topActivity=ComponentInfo{com.android.car.carlauncher/com.android.car.carlauncher.CarLauncher}
  taskId=1000095: com.android.car.carlauncher/com.android.car.carlauncher.CarLauncher bounds=[0,0][1200,800] userId=10 visible=true topActivity=ComponentInfo{com.android.car.carlauncher/com.android.car.carlauncher.CarLauncher}


可以看到其实我们桌面是CarLauncher这个Activity,它是覆盖全屏幕,但是发现居然有个MapsPlaceholderActivity的Activity还在它的上面,显示区域Rect(303, 57 - 1200, 658)就是图片绿色部分,属于地图放置部分

通过dumpsys activity activities可以看出MapsPlaceholderActivity ,CarLauncher两个Activity都属于state=RESUMED状态

大家如果正常理解是不是惊呆了?为啥有两个Activity都是Resumed,正常启动新的Activity时候是不是之前Activity就要Paused,那么这个是在框架怎么实现的不会对之前的Activity进行Paused

解答:

需要解答该问题,其实可以从Activity的是怎么被pause地方进行入手
以前讲解过进入pasue主要pauseBackTasks方法进行

   boolean pauseBackTasks(ActivityRecord resuming) {
      //省略

            leafTask.forAllLeafTaskFragments((taskFrag) -> {
                final ActivityRecord resumedActivity = taskFrag.getResumedActivity();
            
                if (resumedActivity != null && !taskFrag.canBeResumed(resuming)) {
                    if (taskFrag.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")) {
                        someActivityPaused[0]++;
                    }
                }
            }, true /* traverseTopToBottom */);
        }, true /* traverseTopToBottom */);
        return someActivityPaused[0] > 0;
    }

车机CarLauncher的Activity多屏模式WindowingMode为WINDOWING_MODE_MULTI_WINDOW疑问解析

具体可以看下面堆栈:

05-16 22:55:01.987   633  1162 I WindowManager: java.lang.Exception
05-16 22:55:01.987   633  1162 I WindowManager: 	at com.android.server.wm.TaskFragment.resumeTopActivity(TaskFragment.java:1205)
05-16 22:55:01.987   633  1162 I WindowManager: 	at com.android.server.wm.Task.resumeTopActivityInnerLocked(Task.java:5003)
05-16 22:55:01.987   633  1162 I WindowManager: 	at com.android.server.wm.Task.resumeTopActivityUncheckedLocked(Task.java:4938)
05-16 22:55:01.987   633  1162 I WindowManager: 	at com.android.server.wm.RootWindowContainer.resumeFocusedTasksTopActivities(RootWindowContainer.java:2260)
05-16 22:55:01.987   633  1162 I WindowManager: 	at com.android.server.wm.ActivityStarter.startActivityInner(ActivityStarter.java:1935)
05-16 22:55:01.987   633  1162 I WindowManager: 	at com.android.server.wm.ActivityStarter.startActivityUnchecked(ActivityStarter.java:1661)
05-16 22:55:01.987   633  1162 I WindowManager: 	at com.android.server.wm.ActivityStarter.executeRequest(ActivityStarter.java:1216)
05-16 22:55:01.987   633  1162 I WindowManager: 	at com.android.server.wm.ActivityStarter.execute(ActivityStarter.java:702)
05-16 22:55:01.987   633  1162 I WindowManager: 	at com.android.server.wm.ActivityStartController.startActivityInPackage(ActivityStartController.java:283)
05-16 22:55:01.987   633  1162 I WindowManager: 	at com.android.server.wm.ActivityTaskManagerService$LocalService.startActivityInPackage(ActivityTaskManagerService.java:5445)
05-16 22:55:01.987   633  1162 I WindowManager: 	at com.android.server.am.PendingIntentRecord.sendInner(PendingIntentRecord.java:483)
05-16 22:55:01.987   633  1162 I WindowManager: 	at com.android.server.am.PendingIntentRecord.sendWithResult(PendingIntentRecord.java:309)
05-16 22:55:01.987   633  1162 I WindowManager: 	at com.android.server.am.ActivityManagerService.sendIntentSender(ActivityManagerService.java:5384)
05-16 22:55:01.987   633  1162 I WindowManager: 	at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:4402)
05-16 22:55:01.987   633  1162 I WindowManager: 	at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2638)
05-16 22:55:01.987   633  1162 I WindowManager: 	at android.os.Binder.execTransactInternal(Binder.java:1280)
05-16 22:55:01.987   633  1162 I WindowManager: 	at android.os.Binder.execTransact(Binder.java:1244)

如果是正常模式肯定就会进入Pasue,但是WINDOWING_MODE_MULTI_WINDOW不会进入,这个是为啥?那就要具体分析怎么才可以进入这个taskFrag.startPausing的条件:

  if (resumedActivity != null && !taskFrag.canBeResumed(resuming)) {
                    if (taskFrag.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")) {
                        someActivityPaused[0]++;
                    }
                }

这个地方有resumedActivity这个一般就是Carauncher,
resuming就是我们的MapsPlaceholderActivity,
taskFrag就是Carauncher的Task

taskFrag.canBeResumed代表就是这个taskFrag是否可以处于Resumed状态
如果为true则不可以pasue之前activity,如果为false就是要pause前面Activity(CarLauncher)

   boolean canBeResumed(@Nullable ActivityRecord starting) {
        // No need to resume activity in TaskFragment that is not visible.
        return isTopActivityFocusable()
                && getVisibility(starting) == TASK_FRAGMENT_VISIBILITY_VISIBLE;
    }

canBeResumed的判断又是对Task的isTopActivityFocusable()和getVisibility(starting)进行判断,这里isTopActivityFocusable一般都为true,getVisibility是关键,也就是再不进行pause
下面重点看getVisibility实现:

int getVisibility(ActivityRecord starting) {
        //省略部分
        if (parent.asTaskFragment() != null) {
           //省略部分
        final List<TaskFragment> adjacentTaskFragments = new ArrayList<>();
        for (int i = parent.getChildCount() - 1; i >= 0; --i) {
            final WindowContainer other = parent.getChildAt(i);//遍历TaskDisplayarea所有子节点,赋值other
            if (other == null) continue;

            final boolean hasRunningActivities = hasRunningActivity(other);
            if (other == this) {//这里条件是要other和this相等才可以
               //省略部分
                // Should be visible if there is no other fragment occluding it, unless it doesn't
                // have any running activities, not starting one and not home stack.
                //这个地方本身有CarLauncher这个hasRunningActivities满足为true,所以shouldBeVisible为true
                shouldBeVisible = hasRunningActivities
                        || (starting != null && starting.isDescendantOf(this))
                        || isActivityTypeHome();
                break;
            }
			//但是CarLauncher的Task在MapsPlaceholderActivity的底部,所以先遍历到MapsPlaceholderActivity的Task
            final int otherWindowingMode = other.getWindowingMode();
            //关键判断MapsPlaceholderActivity的task的WindowingMode是否属于WINDOWING_MODE_FULLSCREEN,如果属于这里就会return INVISIBLE,这里也就是之前会导致pause的关键,但是因为我们设置成了WINDOWING_MODE_MULTI_WINDOW,所以无法进入这个里面
            if (otherWindowingMode == WINDOWING_MODE_FULLSCREEN) {
                if (isTranslucent(other, starting)) {
                    // Can be visible behind a translucent fullscreen TaskFragment.
                    gotTranslucentFullscreen = true;
                    continue;
                }
                return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
            } else if (otherWindowingMode == WINDOWING_MODE_MULTI_WINDOW
                    && other.matchParentBounds()) {
                    //这里虽然判断了WINDOWING_MODE_MULTI_WINDOW,但是因为MapsPlaceholderActivity的bound区域不是全屏,所以也不会进入这里进行INVISIBLE
                if (isTranslucent(other, starting)) {
                    // Can be visible behind a translucent TaskFragment.
                    gotTranslucentFullscreen = true;
                    continue;
                }
                // Multi-window TaskFragment that matches parent bounds would occlude other children
                return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
            }
           //省略

        if (!shouldBeVisible) {
            return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
        }

        // Lastly - check if there is a translucent fullscreen TaskFragment on top.
        return gotTranslucentFullscreen
                ? TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT
                : TASK_FRAGMENT_VISIBILITY_VISIBLE;
    }

代码较多较复杂,看一两次很难看懂的总结一下:
Visible变量影响关键
1、遍历当前的所有Task,根据先后顺序,一般先遍历的Task肯定是最先的MapsPlaceholderActivity的Task
2、导致会进行Pause关键是如果MapsPlaceholderActivity的Task是WINDOWING_MODE_FULLSCREEN或WINDOWING_MODE_MULTI_WINDOW但是一定要可以覆盖全部下面的Task,说白了就是如果上面Task会把自己覆盖那么就一定会导致INVISIBLE

3、一旦不会覆盖,那么自己Task有正在执行Activity,那么就会返回VISIBLE

具体图如下:

车机CarLauncher的Activity多屏模式WindowingMode为WINDOWING_MODE_MULTI_WINDOW疑问解析
车机CarLauncher的Activity多屏模式WindowingMode为WINDOWING_MODE_MULTI_WINDOW疑问解析文章来源地址https://www.toymoban.com/news/detail-466015.html

到了这里,关于车机CarLauncher的Activity多屏模式WindowingMode为WINDOWING_MODE_MULTI_WINDOW疑问解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • Unity 编译的exe程序,多屏模式下打开应用,应用自动在副屏开启,多用于大屏展示项目。

    Unity 编译的exe程序,多屏模式下打开应用,应用自动在副屏开启,多用于大屏展示项目。

    在展厅大屏项目中我们经常会用到一个电脑显示器+大屏投影或者LED大屏显示的情况,往往是电脑显示器作为主屏控制软件画面开启,大屏作为拓展屏显示软件内容,但是在开启软件时会默认显示在主屏(电脑显示器)上,通常的做法我们需要再将窗口画面拖拽至副屏才可以显

    2024年02月08日
    浏览(13)
  • 温故知新—Activity的五种启动模式

    温故知新—Activity的五种启动模式

    这两天遇到了一个 bug ,说是应用打开一个二级页面,然后直接回到桌面,并不是杀掉应用,只是回到桌面,再次打开的时候没有回到那个二级页面,而是回到了首页。 看到这里,很多人大概都知道是什么原因了,没错,就是 Activity 的启动模式设置为了 singleTask 而导致的问题

    2024年02月09日
    浏览(9)
  • Activity的5种启动模式详解(新增singleInstancePerTask类型)

    Activity的5种启动模式详解(新增singleInstancePerTask类型)

    看到这个标题的时候,也许你会认为我写错了,Activity不是只有四种启动模式吗?分别为startard,singleTop,singleTask,singleInstance这四种。 一般来说是四种,但是android12的时候新加入了singleInstancePerTask类型,所以就有5种了。 介绍这五种类型之前,我们先略微介绍一下这五种类型在源

    2023年04月21日
    浏览(8)
  • Android 白天黑夜模式切换适配及引起的Activity销毁重启解决

    Android 白天黑夜模式切换适配及引起的Activity销毁重启解决

    目录 一、白夜模式切换,Activity销毁重启解决: 二、 暗黑模式适配  1. 添加依赖:   2. 复制下面工具类方法直接使用即可: 3.资源适配:  4. 适配回调: 5.切换白夜模式注意事项:         当白夜模式切换时,activity会销毁重新加载,谷歌是希望重新加载Activity可以刷新页面UI,但我的

    2023年04月20日
    浏览(26)
  • 软件推荐:多屏协作scrcpy

    软件推荐:多屏协作scrcpy

    在百度百科中,关于多屏协作的定义是这样的:通过多屏协作,可以实现跨系统、跨设备协同,让手机与电脑、平板实现资源共享,协同操作,提高工作效率。不要馋华为小米的多屏协同了,来试试这个软件吧!(温馨提示:使用该软件门槛有点高,请酌情观看) 最近因为华

    2023年04月08日
    浏览(11)
  • 电脑怎么设置多屏

    电脑怎么设置多屏

    需求:用笔记本上班,屏幕太小,想要实现一台主机,2个显示屏 操作: ①把桌面显示屏HDMI线接到自己的笔记本,实现共享屏 ②此时右击桌面。在弹出的对话框中选择【显示设置】 然后进去就是选择多屏   左右拖拽鼠标就可以啦 

    2024年02月16日
    浏览(10)
  • 苹果电脑实现华为手机多屏协同

    苹果电脑实现华为手机多屏协同

    网盘地址: https://pan.baidu.com/s/1VVMVljo3EOfmda9tSRPmJg?pwd=u0ja 提取码: u0ja 资源失效可通过公众号「Code工场」回复即可再次获取! 找到下载的文件,右键「 华为电脑管家自动安装器.exe 」课执行程序,然后选择「 以管理员身份运行 」。 程序会打开系统 终端 ,然后执行安装

    2024年02月11日
    浏览(7)
  • Unity指定使用某些屏幕(多屏开发)

    Unity指定使用某些屏幕(多屏开发)

    在一些展示场景中我们会遇到有多个画面需要展示在多个屏幕中的时候,此时很有可能运行我们的项目的设备上还运行着其他展示程序。如果仅仅是多屏展示,那么很有可能在我们的程序打开时抢占了原本正在运行的程序的屏幕。所以我们需要程序能在多屏展示中由我们自己

    2024年02月12日
    浏览(9)
  • Android Graphics 多屏同显/异显

    Android Graphics 多屏同显/异显

    “  亏功一篑,未成丘山。凿井九阶,不次水泽。行百里者半九十,小狐汔济濡其尾。故曰时乎,时不再来。终终始始,是谓君子。 ” 01 — 前言 随着Android智能驾舱系统的普及各种信息交互、影音娱乐场景应用的不断创新, 需要Android Framework开发人员更深入地了解多屏同显

    2024年04月16日
    浏览(9)
  • 长安车机升级公版高德

    长安车机升级公版高德

      密码:gogo 前言 各位工具箱的大佬,于我无关啊,莫名奇妙被点着名骂了,以前都是加了验证然后进群获取卡密,现在已经去掉验证放了。没验证了。 各位工具箱的大佬,于我无关啊,莫名奇妙被点着名骂了,以前都是加了验证然后进群获取卡密,现在已经去掉验证放了。

    2024年02月16日
    浏览(9)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包