diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java index 6373728344a49..435d8eaa563e1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java @@ -45,12 +45,10 @@ import android.app.WindowConfiguration; import android.content.ActivityNotFoundException; import android.content.ClipData; import android.content.ClipDescription; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.LauncherApps; -import android.content.pm.ResolveInfo; import android.graphics.Insets; import android.graphics.Rect; import android.os.Bundle; @@ -64,19 +62,15 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.internal.logging.InstanceId; -import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.R; import com.android.wm.shell.common.DisplayLayout; -import com.android.wm.shell.common.split.SplitLayout; import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition; -import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.splitscreen.SplitScreenController; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; -import java.util.Objects; /** * The policy for handling drag and drop operations to shell. @@ -269,46 +263,10 @@ public class DragAndDropPolicy { mStarter.startShortcut(packageName, id, position, opts, user); } else { final PendingIntent launchIntent = intent.getParcelableExtra(EXTRA_PENDING_INTENT); - mStarter.startIntent(launchIntent, getStartIntentFillInIntent(launchIntent, position), - position, opts); + mStarter.startIntent(launchIntent, null /* fillIntent */, position, opts); } } - /** - * Returns the fill-in intent to use when starting an app from a drop. - */ - @VisibleForTesting - Intent getStartIntentFillInIntent(PendingIntent launchIntent, @SplitPosition int position) { - // Get the drag app - final List infos = launchIntent.queryIntentComponents(0 /* flags */); - final ComponentName dragIntentActivity = !infos.isEmpty() - ? infos.get(0).activityInfo.getComponentName() - : null; - - // Get the current app (either fullscreen or the remaining app post-drop if in splitscreen) - final boolean inSplitScreen = mSplitScreen != null - && mSplitScreen.isSplitScreenVisible(); - final ComponentName currentActivity; - if (!inSplitScreen) { - currentActivity = mSession.runningTaskInfo != null - ? mSession.runningTaskInfo.baseIntent.getComponent() - : null; - } else { - final ActivityManager.RunningTaskInfo nonReplacedTaskInfo = - mSplitScreen.getTaskInfo(SplitLayout.reversePosition(position)); - currentActivity = nonReplacedTaskInfo.baseIntent.getComponent(); - } - - if (Objects.equals(currentActivity, dragIntentActivity)) { - // Only apply MULTIPLE_TASK if we are dragging the same activity - final Intent fillInIntent = new Intent(); - fillInIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Adding MULTIPLE_TASK"); - return fillInIntent; - } - return null; - } - /** * Per-drag session data. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index ee493668994dd..046b1a2541b4e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -18,6 +18,9 @@ package com.android.wm.shell.splitscreen; import static android.app.ActivityManager.START_SUCCESS; import static android.app.ActivityManager.START_TASK_TO_FRONT; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.RemoteAnimationTarget.MODE_OPENING; @@ -58,7 +61,9 @@ import androidx.annotation.IntDef; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.InstanceId; +import com.android.internal.protolog.common.ProtoLog; import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; @@ -74,6 +79,7 @@ import com.android.wm.shell.common.annotations.ExternalThread; import com.android.wm.shell.common.split.SplitLayout; import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition; import com.android.wm.shell.draganddrop.DragAndDropPolicy; +import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.recents.RecentTasksController; import com.android.wm.shell.splitscreen.SplitScreen.StageType; import com.android.wm.shell.transition.LegacyTransitions; @@ -95,7 +101,7 @@ import java.util.concurrent.Executor; */ // TODO(b/198577848): Implement split screen flicker test to consolidate CUJ of split screen. public class SplitScreenController implements DragAndDropPolicy.Starter, - RemoteCallable { + RemoteCallable, ShellTaskOrganizer.FocusListener { private static final String TAG = SplitScreenController.class.getSimpleName(); static final int EXIT_REASON_UNKNOWN = 0; @@ -143,6 +149,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, // outside the bounds of the roots by being reparented into a higher level fullscreen container private SurfaceControl mSplitTasksContainerLayer; + private ActivityManager.RunningTaskInfo mFocusingTaskInfo; + public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue, Context context, RootTaskDisplayAreaOrganizer rootTDAOrganizer, @@ -164,6 +172,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, mLogger = new SplitscreenEventLogger(); mIconProvider = iconProvider; mRecentTasksOptional = recentTasks; + mTaskOrganizer.addFocusListener(this); } public SplitScreen asSplitScreen() { @@ -180,6 +189,11 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, return mMainExecutor; } + @Override + public void onFocusTaskChanged(ActivityManager.RunningTaskInfo taskInfo) { + mFocusingTaskInfo = taskInfo; + } + public void onOrganizerRegistered() { if (mStageCoordinator == null) { // TODO: Multi-display @@ -341,14 +355,21 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, options = mStageCoordinator.resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, null /* wct */); - // Flag this as a no-user-action launch to prevent sending user leaving event to the - // current top activity since it's going to be put into another side of the split. This - // prevents the current top activity from going into pip mode due to user leaving event. if (fillInIntent == null) { fillInIntent = new Intent(); } + // Flag this as a no-user-action launch to prevent sending user leaving event to the + // current top activity since it's going to be put into another side of the split. This + // prevents the current top activity from going into pip mode due to user leaving event. fillInIntent.addFlags(FLAG_ACTIVITY_NO_USER_ACTION); + // Flag with MULTIPLE_TASK if this is launching the same activity into both sides of the + // split. + if (isLaunchingAdjacently(intent.getIntent(), position)) { + fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK"); + } + intent.send(mContext, 0, fillInIntent, null /* onFinished */, null /* handler */, null /* requiredPermission */, options); } catch (PendingIntent.CanceledException e) { @@ -358,6 +379,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, private void startIntentLegacy(PendingIntent intent, @Nullable Intent fillInIntent, @SplitPosition int position, @Nullable Bundle options) { + boolean startSameActivityAdjacently = isLaunchingAdjacently(intent.getIntent(), position); + final WindowContainerTransaction evictWct = new WindowContainerTransaction(); mStageCoordinator.prepareEvictChildTasks(position, evictWct); @@ -368,14 +391,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, IRemoteAnimationFinishedCallback finishedCallback, SurfaceControl.Transaction t) { if (apps == null || apps.length == 0) { - final ActivityManager.RunningTaskInfo pairedTaskInfo = - getTaskInfo(SplitLayout.reversePosition(position)); - final ComponentName pairedActivity = pairedTaskInfo != null - ? pairedTaskInfo.baseIntent.getComponent() : null; - final ComponentName intentActivity = intent.getIntent() != null - ? intent.getIntent().getComponent() : null; - - if (Objects.equals(pairedActivity, intentActivity)) { + if (startSameActivityAdjacently) { // Switch split position if dragging the same activity to another side. setSideStagePosition(SplitLayout.reversePosition( mStageCoordinator.getSideStagePosition())); @@ -417,11 +433,47 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, fillInIntent = new Intent(); } fillInIntent.addFlags(FLAG_ACTIVITY_NO_USER_ACTION); + if (startSameActivityAdjacently) { + fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK"); + } wct.sendPendingIntent(intent, fillInIntent, options); mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct); } + /** Returns {@code true} if it's launching the same component on both sides of the split. */ + @VisibleForTesting + boolean isLaunchingAdjacently(@Nullable Intent startIntent, + @SplitPosition int position) { + if (startIntent == null) { + return false; + } + + final ComponentName launchingActivity = startIntent.getComponent(); + if (launchingActivity == null) { + return false; + } + + if (isSplitScreenVisible()) { + final ActivityManager.RunningTaskInfo pairedTaskInfo = + getTaskInfo(SplitLayout.reversePosition(position)); + final ComponentName pairedActivity = pairedTaskInfo != null + ? pairedTaskInfo.baseIntent.getComponent() : null; + return Objects.equals(launchingActivity, pairedActivity); + } + + if (mFocusingTaskInfo != null + // TODO (b/238032411): have an API to determine whether an activity is valid for + // split screen or not. + && mFocusingTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN + && mFocusingTaskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD) { + return Objects.equals(mFocusingTaskInfo.baseIntent.getComponent(), launchingActivity); + } + + return false; + } + RemoteAnimationTarget[] onGoingToRecentsLegacy(RemoteAnimationTarget[] apps) { if (isSplitScreenVisible()) { // Evict child tasks except the top visible one under split root to ensure it could be diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java index 23eec96a5d8f4..b7777891cfc67 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java @@ -200,11 +200,6 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { @Override @CallSuper public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) { - if (!taskInfo.supportsMultiWindow) { - // Leave split screen if the task no longer supports multi window. - mCallbacks.onNoLongerSupportMultiWindow(); - return; - } if (mRootTaskInfo.taskId == taskInfo.taskId) { // Inflates split decor view only when the root task is visible. if (mRootTaskInfo.isVisible != taskInfo.isVisible) { @@ -217,6 +212,12 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { } mRootTaskInfo = taskInfo; } else if (taskInfo.parentTaskId == mRootTaskInfo.taskId) { + if (!taskInfo.supportsMultiWindow) { + // Leave split screen if the task no longer supports multi window. + mCallbacks.onNoLongerSupportMultiWindow(); + return; + } + mChildrenTaskInfo.put(taskInfo.taskId, taskInfo); mCallbacks.onChildTaskStatusChanged(taskInfo.taskId, true /* present */, taskInfo.isVisible); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java index 7e6595f1abe2c..00617b1a3a3d1 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java @@ -34,7 +34,6 @@ import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPL import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT; import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP; -import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; @@ -57,7 +56,6 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; -import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Insets; @@ -265,62 +263,6 @@ public class DragAndDropPolicyTest { } } - @Test - public void testLaunchMultipleTask_differentActivity() { - setRunningTask(mFullscreenAppTask); - mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId); - Intent fillInIntent = mPolicy.getStartIntentFillInIntent(mock(PendingIntent.class), 0); - assertNull(fillInIntent); - } - - @Test - public void testLaunchMultipleTask_differentActivity_inSplitscreen() { - setRunningTask(mFullscreenAppTask); - doReturn(true).when(mSplitScreenStarter).isSplitScreenVisible(); - doReturn(mFullscreenAppTask).when(mSplitScreenStarter).getTaskInfo(anyInt()); - mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId); - Intent fillInIntent = mPolicy.getStartIntentFillInIntent(mock(PendingIntent.class), 0); - assertNull(fillInIntent); - } - - @Test - public void testLaunchMultipleTask_sameActivity() { - setRunningTask(mFullscreenAppTask); - - // Replace the mocked drag pending intent and ensure it resolves to the same activity - PendingIntent launchIntent = mock(PendingIntent.class); - ResolveInfo launchInfo = new ResolveInfo(); - launchInfo.activityInfo = mFullscreenAppTask.topActivityInfo; - doReturn(Collections.singletonList(launchInfo)) - .when(launchIntent).queryIntentComponents(anyInt()); - mActivityClipData.getItemAt(0).getIntent().putExtra(ClipDescription.EXTRA_PENDING_INTENT, - launchIntent); - - mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId); - Intent fillInIntent = mPolicy.getStartIntentFillInIntent(launchIntent, 0); - assertTrue((fillInIntent.getFlags() & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) != 0); - } - - @Test - public void testLaunchMultipleTask_sameActivity_inSplitScreen() { - setRunningTask(mFullscreenAppTask); - - // Replace the mocked drag pending intent and ensure it resolves to the same activity - PendingIntent launchIntent = mock(PendingIntent.class); - ResolveInfo launchInfo = new ResolveInfo(); - launchInfo.activityInfo = mFullscreenAppTask.topActivityInfo; - doReturn(Collections.singletonList(launchInfo)) - .when(launchIntent).queryIntentComponents(anyInt()); - mActivityClipData.getItemAt(0).getIntent().putExtra(ClipDescription.EXTRA_PENDING_INTENT, - launchIntent); - - doReturn(true).when(mSplitScreenStarter).isSplitScreenVisible(); - doReturn(mFullscreenAppTask).when(mSplitScreenStarter).getTaskInfo(anyInt()); - mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId); - Intent fillInIntent = mPolicy.getStartIntentFillInIntent(launchIntent, 0); - assertTrue((fillInIntent.getFlags() & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) != 0); - } - private Target filterTargetByType(ArrayList targets, int type) { for (Target t : targets) { if (type == t.type) { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java new file mode 100644 index 0000000000000..c90a8259a9efb --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.splitscreen; + +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; + +import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + +import android.app.ActivityManager; +import android.content.ComponentName; +import android.content.Intent; +import android.content.pm.ActivityInfo; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import com.android.launcher3.icons.IconProvider; +import com.android.wm.shell.RootTaskDisplayAreaOrganizer; +import com.android.wm.shell.ShellTaskOrganizer; +import com.android.wm.shell.ShellTestCase; +import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.DisplayImeController; +import com.android.wm.shell.common.DisplayInsetsController; +import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.common.SyncTransactionQueue; +import com.android.wm.shell.common.TransactionPool; +import com.android.wm.shell.recents.RecentTasksController; +import com.android.wm.shell.transition.Transitions; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Optional; + +/** + * Tests for {@link SplitScreenController} + */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class SplitScreenControllerTests extends ShellTestCase { + + @Mock ShellTaskOrganizer mTaskOrganizer; + @Mock SyncTransactionQueue mSyncQueue; + @Mock RootTaskDisplayAreaOrganizer mRootTDAOrganizer; + @Mock ShellExecutor mMainExecutor; + @Mock DisplayController mDisplayController; + @Mock DisplayImeController mDisplayImeController; + @Mock DisplayInsetsController mDisplayInsetsController; + @Mock Transitions mTransitions; + @Mock TransactionPool mTransactionPool; + @Mock IconProvider mIconProvider; + @Mock Optional mRecentTasks; + + private SplitScreenController mSplitScreenController; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mSplitScreenController = spy(new SplitScreenController(mTaskOrganizer, mSyncQueue, mContext, + mRootTDAOrganizer, mMainExecutor, mDisplayController, mDisplayImeController, + mDisplayInsetsController, mTransitions, mTransactionPool, mIconProvider, + mRecentTasks)); + } + + @Test + public void testIsLaunchingAdjacently_notInSplitScreen() { + doReturn(false).when(mSplitScreenController).isSplitScreenVisible(); + + // Verify launching the same activity returns true. + Intent startIntent = createStartIntent("startActivity"); + ActivityManager.RunningTaskInfo focusTaskInfo = + createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, startIntent); + mSplitScreenController.onFocusTaskChanged(focusTaskInfo); + assertTrue(mSplitScreenController.isLaunchingAdjacently( + startIntent, SPLIT_POSITION_TOP_OR_LEFT)); + + // Verify launching different activity returns false. + Intent diffIntent = createStartIntent("diffActivity"); + focusTaskInfo = + createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, diffIntent); + mSplitScreenController.onFocusTaskChanged(focusTaskInfo); + assertFalse(mSplitScreenController.isLaunchingAdjacently( + startIntent, SPLIT_POSITION_TOP_OR_LEFT)); + } + + @Test + public void testIsLaunchingAdjacently_inSplitScreen() { + doReturn(true).when(mSplitScreenController).isSplitScreenVisible(); + + // Verify launching the same activity returns true. + Intent startIntent = createStartIntent("startActivity"); + ActivityManager.RunningTaskInfo pairingTaskInfo = + createTaskInfo(WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD, startIntent); + doReturn(pairingTaskInfo).when(mSplitScreenController).getTaskInfo(anyInt()); + assertTrue(mSplitScreenController.isLaunchingAdjacently( + startIntent, SPLIT_POSITION_TOP_OR_LEFT)); + + // Verify launching different activity returns false. + Intent diffIntent = createStartIntent("diffActivity"); + pairingTaskInfo = + createTaskInfo(WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD, diffIntent); + doReturn(pairingTaskInfo).when(mSplitScreenController).getTaskInfo(anyInt()); + assertFalse(mSplitScreenController.isLaunchingAdjacently( + startIntent, SPLIT_POSITION_TOP_OR_LEFT)); + } + + private Intent createStartIntent(String activityName) { + Intent intent = new Intent(); + intent.setComponent(new ComponentName(mContext, activityName)); + return intent; + } + + private ActivityManager.RunningTaskInfo createTaskInfo(int winMode, int actType, + Intent strIntent) { + ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo(); + info.configuration.windowConfiguration.setActivityType(actType); + info.configuration.windowConfiguration.setWindowingMode(winMode); + info.supportsMultiWindow = true; + info.baseIntent = strIntent; + info.baseActivity = strIntent.getComponent(); + ActivityInfo activityInfo = new ActivityInfo(); + activityInfo.packageName = info.baseActivity.getPackageName(); + activityInfo.name = info.baseActivity.getClassName(); + info.topActivityInfo = activityInfo; + return info; + } +}