CarLauncher Activity multi-screen mode WindowingMode is WINDOWING_MODE_MULTI_WINDOW problem analysis

hi, fans and friends!

   @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,
    })

Today I will introduce to you the multi-window mode related to WindowMode in Activity. This mode is relatively rare, but in the free window mode of split-screen mode, it is very important to have multiple windows. This part is indeed not a normal mode scene, and each mode is relatively difficult. Today, let’s analyze a question about the WINDOWING_MODE_MULTI_WINDOW mode.
More framework core topic reference content
https://ke.qq.com/course/package/83580?tuin=7d4eb354

Question background:

After the WindowMode of the activity is set to WINDOWING_MODE_MULTI_WINDOW, or several other WindowModes other than WINDOWING_MODE_FULLSCREEN, why can multiple Activities be displayed on the same screen, and multiple Activities are in the Resume state.
For example, take our CarLauncher map screen as an example:
insert image description here

For details, you can see the corresponding am stack list to see the situation related to Task and 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}


It can be seen that our desktop is actually the Activity of CarLauncher, which covers the full screen, but found that there is actually an Activity of MapsPlaceholderActivity still on it, and the display area Rect (303, 57 - 1200, 658) is the green part of the picture, which belongs to the map place part

It can be seen from dumpsys activity activities that MapsPlaceholderActivity and CarLauncher both belong to the state=RESUMED state

Are you shocked if you understand it normally? Why are there two activities that are both resumed? When a new activity is started normally, is the previous activity Paused? Then this is how the framework implements it will not Paused the previous activity

answer:

Need to answer this question, in fact, you can start with how the Activity is paused. I
have explained before entering the pauseBackTasks method of the main 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;
    }

insert image description here

You can see the following stack for details:

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)

If it is normal mode, it will definitely enter Pasue, but WINDOWING_MODE_MULTI_WINDOW will not enter, why is this? Then it is necessary to analyze in detail how to enter the condition of taskFrag.startPausing:

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

This place has resumedActivity which is generally Carauncher,
resuming is our MapsPlaceholderActivity,
taskFrag is the Task of Carauncher

taskFrag.canBeResumed represents whether the taskFrag can be in the Resumed state.
If it is true, it cannot pause the previous activity. If it is false, it must pause the previous 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;
    }

The judgment of canBeResumed is to judge the isTopActivityFocusable () and getVisibility (starting) of the Task. Here, isTopActivityFocusable is generally true, and getVisibility is the key, that is, no more pauses. Let's focus on the implementation of 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;
    }

The code is more and more complicated, and it is difficult to understand after reading it once or twice. Summarize:
Visible variables affect the key
1. Traverse all current Tasks. According to the order, the Task that is traversed first must be the first Task of MapsPlaceholderActivity
2. Causes The key to Pause is that if the Task of MapsPlaceholderActivity is WINDOWING_MODE_FULLSCREEN or WINDOWING_MODE_MULTI_WINDOW, it must be able to cover all the following Tasks. To put it bluntly, if the above Task will cover itself, it will definitely lead to INVISIBLE

3. Once it will not be overwritten, then your own Task is executing the Activity, then it will return to VISIBLE

The specific picture is as follows:

insert image description here
insert image description here

Guess you like

Origin blog.csdn.net/learnframework/article/details/130705381