android11实现代码进入分屏、代码退出分屏功能

引言

自android7开始,分屏功能官方就已经实现了。Android11的操作方式是点击rescent键,选择一个应用进入分屏,然后系统会自动在下半屏显示另一个应用。
然后客户是客制化的系统,没有任务栏和状态栏。所以需要开发通过代码进入分屏的方式,并且客户希望可以自由开启一个应用进入上分屏或下分屏,自由退出上分屏或下分屏。这些原生Android11都是没有的,只能新开发。

新开发功能

  • 从taskId进入分屏
  • 启动intent进入分屏
  • 从taskId退出分屏
  • 自由退出分屏
    功能演示

分屏原理说明

首先看一个未分屏状态下的activity栈状态,执行命令

adb shell dumpsys activity activities
  Task display areas in top down Z order:
    TaskDisplayArea DefaultTaskDisplayArea
      mLastOrientationSource=Task{5ebffec #12 visible=true type=standard mode=fullscreen translucent=false A=10099:com.android.dialer U=0 StackId=12 sz=1}
      mPreferredTopFocusableStack=Task{5ebffec #12 visible=true type=standard mode=fullscreen translucent=false A=10099:com.android.dialer U=0 StackId=12 sz=1}
      mLastFocusedStack=Task{5ebffec #12 visible=true type=standard mode=fullscreen translucent=false A=10099:com.android.dialer U=0 StackId=12 sz=1}
      Application tokens in top down Z order:
      * Task{5ebffec #12 visible=true type=standard mode=fullscreen translucent=false A=10099:com.android.dialer U=0 StackId=12 sz=1}
        mLastOrientationSource=ActivityRecord{e499cf9 u0 com.android.dialer/.main.impl.MainActivity t12}
        bounds=[0,0][720,1280]
        * ActivityRecord{e499cf9 u0 com.android.dialer/.main.impl.MainActivity t12}
      * Task{d0d36ff #1 visible=true type=home mode=fullscreen translucent=false I=com.android.launcher3/.uioverrides.QuickstepLauncher U=0 StackId=1 sz=1}
        mLastOrientationSource=Task{da384a7 #10 visible=true type=home mode=fullscreen translucent=false I=com.android.launcher3/.uioverrides.QuickstepLauncher U=0 StackId=1 sz=1}
        bounds=[0,0][720,1280]
        * Task{da384a7 #10 visible=true type=home mode=fullscreen translucent=false I=com.android.launcher3/.uioverrides.QuickstepLauncher U=0 StackId=1 sz=1}
          mLastOrientationSource=ActivityRecord{c16f68e u0 com.android.launcher3/.uioverrides.QuickstepLauncher t10}
          bounds=[0,0][720,1280]
          * ActivityRecord{c16f68e u0 com.android.launcher3/.uioverrides.QuickstepLauncher t10}
      * Task{c140c5 #3 visible=false type=undefined mode=split-screen-primary translucent=true ?? U=0 StackId=3 sz=0}
        bounds=[0,0][720,606]
      * Task{b689f28 #4 visible=false type=undefined mode=split-screen-secondary translucent=true ?? U=0 StackId=4 sz=0}
        bounds=[0,626][720,1280]

看最后两个task,他们分属于不同的stackId,且都有不同的mode和bounds,mode分别是split-screen-primary和split-screen-secondary。split-screen-primary表示上半屏,且bounds=[0,0][720,606]就是处在上半屏的位置;split-screen-secondary表示下半屏,bounds=[0,626][720,1280]就是处在下半屏的位置。
Android系统其实就是根据stack来实现分屏的,系统启动之初就创建好了几个主要的stack,每个stack规定了自己的bounds和mode,bounds即大小和显示位置,mode即显示模式。Android系统中的每一个Activity都位于一个Task中,每个task都位于一个ActivityStack中。
全屏模式下大部分activity都处于fullscreen模式下的activityStack,把要分屏显示的activity的task移入分屏ActivityStack即可分屏显示。

从taskId进入分屏

原生android11只支持设置一个taskId显示在上半屏进入分屏状态,我这里实现的可以根据参数设置一个taskId进入上分屏或下分屏。
有四个方法可以实现,分别是:

1 ActivityTaskManager.setTaskWindowingMode(int taskId, int windowingMode, boolean toTop)
2 ActivityTaskManager.setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop, boolean animate, Rect initialBounds, boolean showRecents)
3
//注:原生android11只支持进入上分屏
final ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchWindowingMode(true ? WINDOWING_MODE_SPLIT_SCREEN_PRIMARY : WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
options.setSplitScreenCreateMode(true ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT);
ActivityTaskManager.getService().startActivityFromRecents(getTaskId(), options.toBundle())
4
//注:此方法只适合在已经分屏状态下启动activity进入下半屏
Intent intent = new Intent("android.settings.SETTINGS");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);
startActivity(intent);

启动intent进入分屏

原生android11只支持在已经分屏状态下启动activity显示在另半屏,我这里实现的可以根据参数设置启动intent进入上分屏或下分屏。

Intent intent = new Intent(this, SubActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT_ARBITRARY);
intent.putExtra("showOnSpliteScreenPrimary", inflate.cbShowInSplitePrimary.isChecked());
startActivity(intent);

从taskId退出分屏

//第二个参数是WindowConfiguration.WINDOWING_MODE_FULLSCREEN
ActivityTaskManager.setTaskWindowingMode(int taskId, int windowingMode, boolean toTop)

自由退出分屏

//此功能新增的,show_splitScreenPrimary指定全屏显示上半屏幕或下半屏。
ActivityTaskManager.getService().exitSpliteScreenMode(show_splitScreenPrimary);

功能实现

上面是罗列客户端的使用接口,下面贴出修改点。
关键修改类:

frameworks/base/core/java/android/content/Intent.java
frameworks/base/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
frameworks/base/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
frameworks/base/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
frameworks/base/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
frameworks/base/services/core/java/com/android/server/wm/TaskDisplayArea.java

修改如下:

diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 24d59a0826c8..8fd92d171cf6 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -6451,7 +6451,8 @@ public class Intent implements Parcelable, Cloneable {
      * required if you want a new instance of an existing activity to be created.
      */
     public static final int FLAG_ACTIVITY_LAUNCH_ADJACENT = 0x00001000;
-
+    //huanghp add: to enable startActivity into splite-screen-mode
+    public static final int FLAG_ACTIVITY_LAUNCH_ADJACENT_ARBITRARY = 0x00001001;
 
     /**
      * If set in an Intent passed to {@link Context#startActivity Context.startActivity()},

diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 570a4bb3cd12..4ae96665f635 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -523,7 +523,8 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
         update(mDisplayController.getDisplayContext(
                 mContext.getDisplayId()).getResources().getConfiguration());
         // Set resizable directly here because applyEnterSplit already resizes home stack.
-        mHomeStackResizable = mWindowManagerProxy.applyEnterSplit(mSplits, mSplitLayout);
+        //huanghp modify:for apply to different split screen states
+        mHomeStackResizable = mWindowManagerProxy.applyEnterSplit2(mSplits, mSplitLayout);
     }
 
     void startDismissSplit() {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
index 7a313dc0622b..c8e816f3c02f 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
@@ -214,6 +214,17 @@ class SplitScreenTaskOrganizer extends TaskOrganizer {
                     Log.d(TAG, "   was not in split, but primary is populated, so enter it");
                 }
                 mDivider.startEnterSplit();
+                //huanghp add: to enable start splite-screen-mode from secondary splite
+            } else if (!secondaryIsEmpty && primaryWasEmpty && secondaryWasEmpty) {
+                // Wasn't in split-mode (both were empty), but now that the secondary split is
+                // populated, we should fully enter split by moving everything else into primary.
+                // This just tells window-manager to reparent things, the UI will respond
+                // when it gets new task info for the primary split.
+                if (DEBUG) {
+                    Log.d(TAG, "   was not in split, but secondary is populated, so enter it");
+                }
+                mDivider.startEnterSplit();
+                //huanghp end
             }
         } else if (secondaryImpliesMinimize) {
             // Both splits are populated but the secondary split has a home/recents stack on top,
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index 410e3dd39a0b..b13f4195fca7 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -18,6 +18,7 @@ package com.android.systemui.stackdivider;
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
@@ -229,6 +230,51 @@ public class WindowManagerProxy {
         return isHomeResizable;
     }
 
+    //huanghp add: to support moveTaskToStack split-screen-secondary by systemui
+    boolean applyEnterSplit2(SplitScreenTaskOrganizer tiles, SplitDisplayLayout layout) {
+        // Set launchtile first so that any stack created after
+        // getAllStackInfos and before reparent (even if unlikely) are placed
+        // correctly.
+        final boolean primaryIsEmpty = tiles.mPrimary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
+        TaskOrganizer.setLaunchRoot(DEFAULT_DISPLAY, primaryIsEmpty ? tiles.mPrimary.token: tiles.mSecondary.token);
+        List<ActivityManager.RunningTaskInfo> rootTasks =
+                TaskOrganizer.getRootTasks(DEFAULT_DISPLAY, null /* activityTypes */);
+        WindowContainerTransaction wct = new WindowContainerTransaction();
+        if (rootTasks.isEmpty()) {
+            return false;
+        }
+        ActivityManager.RunningTaskInfo topHomeTask = null;
+        for (int i = rootTasks.size() - 1; i >= 0; --i) {
+            final ActivityManager.RunningTaskInfo rootTask = rootTasks.get(i);
+            // Only move resizeable task to split secondary. However, we have an exception
+            // for non-resizable home because we will minimize to show it.
+            if (!rootTask.isResizeable && rootTask.topActivityType != ACTIVITY_TYPE_HOME) {
+                continue;
+            }
+            // Only move fullscreen tasks to split secondary.
+            if (rootTask.configuration.windowConfiguration.getWindowingMode()
+                    != WINDOWING_MODE_FULLSCREEN) {
+                continue;
+            }
+            // Since this iterates from bottom to top, update topHomeTask for every fullscreen task
+            // so it will be left with the status of the top one.
+            topHomeTask = isHomeOrRecentTask(rootTask) ? rootTask : null;
+            wct.reparent(rootTask.token, primaryIsEmpty ? tiles.mPrimary.token: tiles.mSecondary.token, true /* onTop */);
+        }
+        // Move the secondary split-forward.
+        wct.reorder(primaryIsEmpty ? tiles.mPrimary.token: tiles.mSecondary.token, true /* onTop */);
+        boolean isHomeResizable = applyHomeTasksMinimized(layout, null /* parent */, wct);
+        if (topHomeTask != null) {
+            // Translate/update-crop of secondary out-of-band with sync transaction -- Until BALST
+            // is enabled, this temporarily syncs the home surface position with offset until
+            // sync transaction finishes.
+            wct.setBoundsChangeTransaction(topHomeTask.token, tiles.mHomeBounds);
+        }
+        applySyncTransaction(wct);
+        return isHomeResizable;
+    }
+    //huanghp end
+
     static boolean isHomeOrRecentTask(ActivityManager.RunningTaskInfo ti) {
         final int atype = ti.configuration.windowConfiguration.getActivityType();
         return atype == ACTIVITY_TYPE_HOME || atype == ACTIVITY_TYPE_RECENTS;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 4c883805ec8e..f96c42c531ef 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -36,6 +36,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
 import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
+import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT_ARBITRARY;
 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -110,6 +111,7 @@ import android.service.voice.IVoiceInteractionSession;
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.DebugUtils;
+import android.util.Log;
 import android.util.Pools.SynchronizedPool;
 import android.util.Slog;
 
@@ -1795,6 +1797,18 @@ class ActivityStarter {
             }
             mOptions.setLaunchWindowingMode(windowingMode);
         }
+        //huanghp add: for enable to enter splite-screen from startActivity
+        else if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT_ARBITRARY)!=0){
+            boolean showOnSpliteScreenPrimary = r.intent.getBooleanExtra("showOnSpliteScreenPrimary", false);
+            int windowingMode = showOnSpliteScreenPrimary ? WINDOWING_MODE_SPLIT_SCREEN_PRIMARY : WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+            if (mOptions == null) {
+                mOptions = ActivityOptions.makeBasic();
+            }
+            mOptions.setLaunchWindowingMode(windowingMode);
+            Log.w(TAG, "computeLaunchParams() called with: r = [" + r + "], sourceRecord = ["
+                    + sourceRecord + "], targetTask = [" + targetTask + "], showOnSpliteScreenPrimary="+ showOnSpliteScreenPrimary + "]");
+        }
+        //huanghp end
 
         mSupervisor.getLaunchParamsController().calculate(targetTask, r.info.windowLayout, r,
                 sourceRecord, mOptions, PHASE_BOUNDS, mLaunchParams);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index b664bb7d9d78..f99c753f73a4 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2389,6 +2389,39 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
         return null;
     }
 
+    @Override
+    public boolean exitSpliteScreenMode(boolean show_splitScreenPrimary){
+        Log.d(TAG, "exitSpliteScreenMode() called with: showPrimaryScreen = [" + show_splitScreenPrimary + "]");
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "setTaskWindowingMode()");
+        synchronized (mGlobalLock) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer.getDisplayContent(
+                        DEFAULT_DISPLAY).getDefaultTaskDisplayArea();
+                ActivityStack rootSplitScreenPrimaryTask = defaultTaskDisplayArea.getRootSplitScreenPrimaryTask();
+                ActivityStack rootSplitScreenSecondaryTask = defaultTaskDisplayArea.getRootSplitScreenSecondaryTask();
+                if (show_splitScreenPrimary){
+                    if (rootSplitScreenPrimaryTask!=null){
+                        Task topMostTask = rootSplitScreenPrimaryTask.getTopMostTask();
+                        if (topMostTask!=null){
+                            return setTaskWindowingMode(topMostTask.mTaskId, WINDOWING_MODE_FULLSCREEN, true);
+                        }
+                    }
+                }else if (rootSplitScreenSecondaryTask!=null){
+                    Task topMostTask = rootSplitScreenSecondaryTask.getTopMostTask();
+                    if (topMostTask!=null){
+                        return setTaskWindowingMode(topMostTask.mTaskId, WINDOWING_MODE_FULLSCREEN, true);
+                    }
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+        return false;
+    }
+
     @Override
     public boolean setTaskWindowingMode(int taskId, int windowingMode, boolean toTop) {
         if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
@@ -2437,6 +2470,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
         }
     }
 
+    @Override
+    public void toggleSplitScreen() throws RemoteException {
+
+    }
+
     @Override
     public String getCallingPackage(IBinder token) {
         synchronized (mGlobalLock) {
@@ -2846,8 +2884,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
             // The task is already in split-screen and with correct windowing mode.
             return true;
         }
-
-        moveTaskToSplitScreenPrimaryTask(task, toTop);
+        //huanghp modify
+        if (windowingMode== WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY){
+            moveTaskToSplitScreenPrimaryTask(task, toTop);
+        }else moveTaskToSplitScreenSecondaryTask(task, toTop);
+        //huanghp end
         return prevMode != task.getWindowingMode();
     }
 
@@ -2871,6 +2912,31 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
         mWindowOrganizerController.applyTransaction(wct);
     }
 
+    //huanghp add
+    void moveTaskToSplitScreenSecondaryTask(Task task, boolean toTop) {
+        Log.d(TAG,
+                "moveTaskToSplitScreenSecondaryTask() called with: task = [" + task + "], toTop = ["
+                        + toTop + "]");
+        final TaskDisplayArea taskDisplayArea = task.getDisplayArea();
+        final ActivityStack secondarySplitTask = taskDisplayArea.getRootSplitScreenSecondaryTask();
+        if (secondarySplitTask == null) {
+            throw new IllegalStateException("Can't enter split without associated organized task");
+        }
+
+        if (toTop) {
+            taskDisplayArea.positionStackAt(POSITION_TOP, secondarySplitTask,
+                    false /* includingParents */);
+        }
+        WindowContainerTransaction wct = new WindowContainerTransaction();
+        // Clear out current windowing mode before reparenting to split taks.
+        wct.setWindowingMode(
+                task.getStack().mRemoteToken.toWindowContainerToken(), WINDOWING_MODE_UNDEFINED);
+        wct.reparent(task.getStack().mRemoteToken.toWindowContainerToken(),
+                secondarySplitTask.mRemoteToken.toWindowContainerToken(), toTop);
+        mWindowOrganizerController.applyTransaction(wct);
+    }
+    //huanghp end
+
     /**
      * Removes stacks in the input windowing modes from the system if they are of activity type
      * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 5c1b6eefcecc..41cded3f35fc 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -27,6 +27,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
@@ -133,6 +134,7 @@ import android.service.voice.IVoiceInteractionSession;
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
 import android.util.IntArray;
+import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -3008,23 +3010,36 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
         if (!r.canBeLaunchedOnDisplay(taskDisplayArea.getDisplayId())) {
             return null;
         }
+        //huanghp add: to get the desired splite-window-mode
+        int expectWindowMode=-1;
+        if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT_ARBITRARY)!=0){
+            boolean showOnSpliteScreenPrimary = r.intent.getBooleanExtra("showOnSpliteScreenPrimary", false);
+            expectWindowMode= showOnSpliteScreenPrimary? WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+        }
+        //huanghp end
 
         // If {@code r} is already in target display area and its task is the same as the candidate
         // task, the intention should be getting a launch stack for the reusable activity, so we can
         // use the existing stack.
         if (candidateTask != null && (r.getTask() == null || r.getTask() == candidateTask)) {
-            // TODO(b/153920825): Fix incorrect evaluation of attached state
-            final TaskDisplayArea attachedTaskDisplayArea = r.getTask() != null
-                    ? r.getTask().getDisplayArea() : r.getDisplayArea();
-            if (attachedTaskDisplayArea == null || attachedTaskDisplayArea == taskDisplayArea) {
-                return candidateTask.getStack();
-            }
-            // Or the candidate task is already a root task that can be reused by reparenting
-            // it to the target display.
-            if (candidateTask.isRootTask()) {
-                final ActivityStack stack = candidateTask.getStack();
-                stack.reparent(taskDisplayArea, true /* onTop */);
-                return stack;
+            //huanghp add
+            if (expectWindowMode!=-1 && expectWindowMode!=candidateTask.getWindowingMode()){
+                Log.w(TAG, "getValidLaunchStackInTaskDisplayArea: with expectWindowMode different");
+            }else {
+                huanghp end
+                // TODO(b/153920825): Fix incorrect evaluation of attached state
+                final TaskDisplayArea attachedTaskDisplayArea = r.getTask() != null
+                        ? r.getTask().getDisplayArea() : r.getDisplayArea();
+                if (attachedTaskDisplayArea == null || attachedTaskDisplayArea == taskDisplayArea) {
+                    return candidateTask.getStack();
+                }
+                // Or the candidate task is already a root task that can be reused by reparenting
+                // it to the target display.
+                if (candidateTask.isRootTask()) {
+                    final ActivityStack stack = candidateTask.getStack();
+                    stack.reparent(taskDisplayArea, true /* onTop */);
+                    return stack;
+                }
             }
         }
 
@@ -3072,6 +3087,18 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
         }
         if (stack.mCreatedByOrganizer) {
             // Don't launch directly into task created by organizer...but why can't we?
+            //huanghp add: to enable launch activity into splite-screen-mode
+            if (r.supportsSplitScreenWindowingMode() && (r.intent.getFlags()&Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT_ARBITRARY)!=0){
+                boolean showOnSpliteScreenPrimary = r.intent.getBooleanExtra("showOnSpliteScreenPrimary", false);
+                if ((showOnSpliteScreenPrimary && stack.getWindowingMode()==WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && windowingMode==WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
+                || (!showOnSpliteScreenPrimary && stack.getWindowingMode()==WINDOWING_MODE_SPLIT_SCREEN_SECONDARY && windowingMode==WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)){
+                    Log.w(TAG, "isValidLaunchStack() called with FLAG_ACTIVITY_LAUNCH_ADJACENT_ARBITRARY: stack = [" + stack + "], r = [" + r + "], windowingMode = [" + windowingMode + "]");
+                    return true;
+                }
+            }
+            Log.w(TAG, "isValidLaunchStack() called with##stack.mCreatedByOrganizer: stack = [" + stack + "], r = [" + r
+                    + "], windowingMode = [" + windowingMode + "]");
+            //huanghp end
             return false;
         }
         // There is a 1-to-1 relationship between stack and task when not in
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 79f3b8340b21..eccd3594ece6 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -1480,6 +1480,13 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
             // Switch to the display's windowing mode if we are not in split-screen mode and we are
             // trying to launch in split-screen secondary.
             windowingMode = WINDOWING_MODE_UNDEFINED;
+            //huanghp add: enable to launch in split-screen secondary or primary
+            if (r!=null && (r.intent.getFlags()&Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT_ARBITRARY)!=0){
+                boolean showOnSpliteScreenPrimary = r.intent.getBooleanExtra(
+                        "showOnSpliteScreenPrimary", false);
+                windowingMode= showOnSpliteScreenPrimary? WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:WINDOWING_MODE_SPLIT_SCREEN_SECONDARY ;
+            }
+            //huanghp end
         } else if (inSplitScreenMode && windowingMode == WINDOWING_MODE_UNDEFINED) {
             windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
         }
-- 
2.34.1

end,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值