From 3589fb907fef9bfb60a2166b0980ef57ef97e887 Mon Sep 17 00:00:00 2001 From: Charles Chen Date: Tue, 13 Sep 2022 22:39:10 +0800 Subject: [PATCH] Add TaskFragmentParentInfo This CL adds a TaskFragmentParentInfo class and extends onTaskFragmentParentInfoChanged to dispatch display ID and visibility of the parent Task. It makes SplitController able to track visibility and display changes and used to update SplitContainers if there's a folding state change. Test: atest SplitControllerTest TaskFragmentOrganizerControllerTest Bug: 243609832 Bug: 207494880 Change-Id: If3d5db621b20d4005ce0b60e46ac98e1d1e962e3 --- .../java/android/window/TaskFragmentInfo.java | 4 + .../window/TaskFragmentParentInfo.aidl | 23 ++++ .../window/TaskFragmentParentInfo.java | 130 ++++++++++++++++++ .../window/TaskFragmentTransaction.java | 36 +++-- .../extensions/embedding/SplitController.java | 10 +- .../embedding/SplitControllerTest.java | 9 +- .../core/java/com/android/server/wm/Task.java | 9 ++ .../wm/TaskFragmentOrganizerController.java | 27 ++-- .../TaskFragmentOrganizerControllerTest.java | 15 +- 9 files changed, 231 insertions(+), 32 deletions(-) create mode 100644 core/java/android/window/TaskFragmentParentInfo.aidl create mode 100644 core/java/android/window/TaskFragmentParentInfo.java diff --git a/core/java/android/window/TaskFragmentInfo.java b/core/java/android/window/TaskFragmentInfo.java index 56e910769cb5a..e2c8a31cc987e 100644 --- a/core/java/android/window/TaskFragmentInfo.java +++ b/core/java/android/window/TaskFragmentInfo.java @@ -188,6 +188,10 @@ public final class TaskFragmentInfo implements Parcelable { /** * Returns {@code true} if the parameters that are important for task fragment organizers are * equal between this {@link TaskFragmentInfo} and {@param that}. + * Note that this method is usually called with + * {@link com.android.server.wm.WindowOrganizerController#configurationsAreEqualForOrganizer( + * Configuration, Configuration)} to determine if this {@link TaskFragmentInfo} should + * be dispatched to the client. */ public boolean equalsForTaskFragmentOrganizer(@Nullable TaskFragmentInfo that) { if (that == null) { diff --git a/core/java/android/window/TaskFragmentParentInfo.aidl b/core/java/android/window/TaskFragmentParentInfo.aidl new file mode 100644 index 0000000000000..79d2209ab244a --- /dev/null +++ b/core/java/android/window/TaskFragmentParentInfo.aidl @@ -0,0 +1,23 @@ +/* + * 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 android.window; + +/** + * The information about the parent Task of a particular TaskFragment + * @hide + */ +parcelable TaskFragmentParentInfo; \ No newline at end of file diff --git a/core/java/android/window/TaskFragmentParentInfo.java b/core/java/android/window/TaskFragmentParentInfo.java new file mode 100644 index 0000000000000..c89a54e90f58e --- /dev/null +++ b/core/java/android/window/TaskFragmentParentInfo.java @@ -0,0 +1,130 @@ +/* + * 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 android.window; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.WindowConfiguration; +import android.content.res.Configuration; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * The information about the parent Task of a particular TaskFragment + * @hide + */ +public class TaskFragmentParentInfo implements Parcelable { + @NonNull + private final Configuration mConfiguration = new Configuration(); + + private final int mDisplayId; + + private final boolean mVisibleRequested; + + public TaskFragmentParentInfo(@NonNull Configuration configuration, int displayId, + boolean visibleRequested) { + mConfiguration.setTo(configuration); + mDisplayId = displayId; + mVisibleRequested = visibleRequested; + } + + public TaskFragmentParentInfo(@NonNull TaskFragmentParentInfo info) { + mConfiguration.setTo(info.getConfiguration()); + mDisplayId = info.mDisplayId; + mVisibleRequested = info.mVisibleRequested; + } + + /** The {@link Configuration} of the parent Task */ + @NonNull + public Configuration getConfiguration() { + return mConfiguration; + } + + /** + * The display ID of the parent Task. {@link android.view.Display#INVALID_DISPLAY} means the + * Task is detached from previously associated display. + */ + public int getDisplayId() { + return mDisplayId; + } + + /** Whether the parent Task is requested to be visible or not */ + public boolean isVisibleRequested() { + return mVisibleRequested; + } + + /** + * Returns {@code true} if the parameters which are important for task fragment + * organizers are equal between this {@link TaskFragmentParentInfo} and {@code that}. + * Note that this method is usually called with + * {@link com.android.server.wm.WindowOrganizerController#configurationsAreEqualForOrganizer( + * Configuration, Configuration)} to determine if this {@link TaskFragmentParentInfo} should + * be dispatched to the client. + */ + public boolean equalsForTaskFragmentOrganizer(@Nullable TaskFragmentParentInfo that) { + if (that == null) { + return false; + } + return getWindowingMode() == that.getWindowingMode() && mDisplayId == that.mDisplayId + && mVisibleRequested == that.mVisibleRequested; + } + + @WindowConfiguration.WindowingMode + private int getWindowingMode() { + return mConfiguration.windowConfiguration.getWindowingMode(); + } + + @Override + public String toString() { + return TaskFragmentParentInfo.class.getSimpleName() + ":{" + + "config=" + mConfiguration + + ", displayId=" + mDisplayId + + ", visibleRequested=" + mVisibleRequested + + "}"; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + mConfiguration.writeToParcel(dest, flags); + dest.writeInt(mDisplayId); + dest.writeBoolean(mVisibleRequested); + } + + private TaskFragmentParentInfo(Parcel in) { + mConfiguration.readFromParcel(in); + mDisplayId = in.readInt(); + mVisibleRequested = in.readBoolean(); + } + + public static final Creator CREATOR = + new Creator() { + @Override + public TaskFragmentParentInfo createFromParcel(Parcel in) { + return new TaskFragmentParentInfo(in); + } + + @Override + public TaskFragmentParentInfo[] newArray(int size) { + return new TaskFragmentParentInfo[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } +} diff --git a/core/java/android/window/TaskFragmentTransaction.java b/core/java/android/window/TaskFragmentTransaction.java index 413c0dd77ed66..a8216069bd534 100644 --- a/core/java/android/window/TaskFragmentTransaction.java +++ b/core/java/android/window/TaskFragmentTransaction.java @@ -171,10 +171,6 @@ public final class TaskFragmentTransaction implements Parcelable { /** @see #setTaskId(int) */ private int mTaskId; - /** @see #setTaskConfiguration(Configuration) */ - @Nullable - private Configuration mTaskConfiguration; - /** @see #setErrorCallbackToken(IBinder) */ @Nullable private IBinder mErrorCallbackToken; @@ -191,6 +187,9 @@ public final class TaskFragmentTransaction implements Parcelable { @Nullable private IBinder mActivityToken; + @Nullable + private TaskFragmentParentInfo mTaskFragmentParentInfo; + public Change(@ChangeType int type) { mType = type; } @@ -200,11 +199,11 @@ public final class TaskFragmentTransaction implements Parcelable { mTaskFragmentToken = in.readStrongBinder(); mTaskFragmentInfo = in.readTypedObject(TaskFragmentInfo.CREATOR); mTaskId = in.readInt(); - mTaskConfiguration = in.readTypedObject(Configuration.CREATOR); mErrorCallbackToken = in.readStrongBinder(); mErrorBundle = in.readBundle(TaskFragmentTransaction.class.getClassLoader()); mActivityIntent = in.readTypedObject(Intent.CREATOR); mActivityToken = in.readStrongBinder(); + mTaskFragmentParentInfo = in.readTypedObject(TaskFragmentParentInfo.CREATOR); } @Override @@ -213,11 +212,11 @@ public final class TaskFragmentTransaction implements Parcelable { dest.writeStrongBinder(mTaskFragmentToken); dest.writeTypedObject(mTaskFragmentInfo, flags); dest.writeInt(mTaskId); - dest.writeTypedObject(mTaskConfiguration, flags); dest.writeStrongBinder(mErrorCallbackToken); dest.writeBundle(mErrorBundle); dest.writeTypedObject(mActivityIntent, flags); dest.writeStrongBinder(mActivityToken); + dest.writeTypedObject(mTaskFragmentParentInfo, flags); } /** The change is related to the TaskFragment created with this unique token. */ @@ -241,10 +240,10 @@ public final class TaskFragmentTransaction implements Parcelable { return this; } + // TODO(b/241043377): Keep this API to prevent @TestApi changes. Remove in the next release. /** Configuration of the parent Task. */ @NonNull public Change setTaskConfiguration(@NonNull Configuration configuration) { - mTaskConfiguration = requireNonNull(configuration); return this; } @@ -292,6 +291,19 @@ public final class TaskFragmentTransaction implements Parcelable { return this; } + // TODO(b/241043377): Hide this API to prevent @TestApi changes. Remove in the next release. + /** + * Sets info of the parent Task of the embedded TaskFragment. + * @see TaskFragmentParentInfo + * + * @hide pending unhide + */ + @NonNull + public Change setTaskFragmentParentInfo(@NonNull TaskFragmentParentInfo info) { + mTaskFragmentParentInfo = requireNonNull(info); + return this; + } + @ChangeType public int getType() { return mType; @@ -311,9 +323,10 @@ public final class TaskFragmentTransaction implements Parcelable { return mTaskId; } + // TODO(b/241043377): Keep this API to prevent @TestApi changes. Remove in the next release. @Nullable public Configuration getTaskConfiguration() { - return mTaskConfiguration; + return mTaskFragmentParentInfo.getConfiguration(); } @Nullable @@ -337,6 +350,13 @@ public final class TaskFragmentTransaction implements Parcelable { return mActivityToken; } + // TODO(b/241043377): Hide this API to prevent @TestApi changes. Remove in the next release. + /** @hide pending unhide */ + @Nullable + public TaskFragmentParentInfo getTaskFragmentParentInfo() { + return mTaskFragmentParentInfo; + } + @Override public String toString() { return "Change{ type=" + mType + " }"; diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java index 126f8350839cc..f088d5a9e4132 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -63,6 +63,7 @@ import android.util.Pair; import android.util.Size; import android.util.SparseArray; import android.window.TaskFragmentInfo; +import android.window.TaskFragmentParentInfo; import android.window.TaskFragmentTransaction; import android.window.WindowContainerTransaction; @@ -191,7 +192,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen onTaskFragmentVanished(wct, info); break; case TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED: - onTaskFragmentParentInfoChanged(wct, taskId, change.getTaskConfiguration()); + onTaskFragmentParentInfoChanged(wct, taskId, + change.getTaskFragmentParentInfo()); break; case TYPE_TASK_FRAGMENT_ERROR: final Bundle errorBundle = change.getErrorBundle(); @@ -346,12 +348,14 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen * * @param wct The {@link WindowContainerTransaction} to make any changes with if needed. * @param taskId Id of the parent Task that is changed. - * @param parentConfig Config of the parent Task. + * @param parentInfo {@link TaskFragmentParentInfo} of the parent Task. */ @VisibleForTesting @GuardedBy("mLock") void onTaskFragmentParentInfoChanged(@NonNull WindowContainerTransaction wct, - int taskId, @NonNull Configuration parentConfig) { + int taskId, @NonNull TaskFragmentParentInfo parentInfo) { + // TODO(b/241043111): handles displayId and visibility here. + final Configuration parentConfig = parentInfo.getConfiguration(); onTaskConfigurationChanged(taskId, parentConfig); if (isInPictureInPicture(parentConfig)) { // No need to update presentation in PIP until the Task exit PIP. diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java index 58870a66feea1..f5734b8b3bff0 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java @@ -19,6 +19,7 @@ package androidx.window.extensions.embedding; import static android.app.ActivityManager.START_CANCELED; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static android.view.Display.DEFAULT_DISPLAY; import static android.window.TaskFragmentTransaction.TYPE_ACTIVITY_REPARENTED_TO_TASK; import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED; import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_ERROR; @@ -75,6 +76,7 @@ import android.os.IBinder; import android.platform.test.annotations.Presubmit; import android.window.TaskFragmentInfo; import android.window.TaskFragmentOrganizer; +import android.window.TaskFragmentParentInfo; import android.window.TaskFragmentTransaction; import android.window.WindowContainerTransaction; @@ -1038,15 +1040,16 @@ public class SplitControllerTest { @Test public void testOnTransactionReady_taskFragmentParentInfoChanged() { final TaskFragmentTransaction transaction = new TaskFragmentTransaction(); - final Configuration taskConfig = new Configuration(); + final TaskFragmentParentInfo parentInfo = new TaskFragmentParentInfo(Configuration.EMPTY, + DEFAULT_DISPLAY, true); transaction.addChange(new TaskFragmentTransaction.Change( TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED) .setTaskId(TASK_ID) - .setTaskConfiguration(taskConfig)); + .setTaskFragmentParentInfo(parentInfo)); mSplitController.onTransactionReady(transaction); verify(mSplitController).onTaskFragmentParentInfoChanged(any(), eq(TASK_ID), - eq(taskConfig)); + eq(parentInfo)); verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any(), anyInt(), anyBoolean()); } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 91db27861a38f..85083a131373c 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -185,6 +185,7 @@ import android.view.WindowManager.TransitionOldType; import android.window.ITaskOrganizer; import android.window.PictureInPictureSurfaceTransaction; import android.window.StartingWindowInfo; +import android.window.TaskFragmentParentInfo; import android.window.TaskSnapshot; import android.window.WindowContainerToken; @@ -3518,6 +3519,14 @@ class Task extends TaskFragment { return info; } + /** + * Returns the {@link TaskFragmentParentInfo} which will send to the client + * {@link android.window.TaskFragmentOrganizer} + */ + TaskFragmentParentInfo getTaskFragmentParentInfo() { + return new TaskFragmentParentInfo(getConfiguration(), getDisplayId(), isVisibleRequested()); + } + boolean isTaskId(int taskId) { return mTaskId == taskId; } diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java index 8c037a7390b15..c4d3e3730abea 100644 --- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java @@ -49,6 +49,7 @@ import android.view.WindowManager; import android.window.ITaskFragmentOrganizer; import android.window.ITaskFragmentOrganizerController; import android.window.TaskFragmentInfo; +import android.window.TaskFragmentParentInfo; import android.window.TaskFragmentTransaction; import android.window.WindowContainerTransaction; @@ -118,10 +119,10 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr private final Map mTaskFragmentTaskIds = new WeakHashMap<>(); /** - * Map from {@link Task#mTaskId} to the last Task {@link Configuration} sent to the + * Map from {@link Task#mTaskId} to the last {@link TaskFragmentParentInfo} sent to the * organizer. */ - private final SparseArray mLastSentTaskFragmentParentConfigs = + private final SparseArray mLastSentTaskFragmentParentInfos = new SparseArray<>(); /** @@ -225,7 +226,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr taskId = mTaskFragmentTaskIds.remove(tf); if (!mTaskFragmentTaskIds.containsValue(taskId)) { // No more TaskFragment in the Task. - mLastSentTaskFragmentParentConfigs.remove(taskId); + mLastSentTaskFragmentParentInfos.remove(taskId); } } else { // This can happen if the appeared wasn't sent before remove. @@ -260,25 +261,27 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } @Nullable - TaskFragmentTransaction.Change prepareTaskFragmentParentInfoChanged( - @NonNull Task task) { + TaskFragmentTransaction.Change prepareTaskFragmentParentInfoChanged(@NonNull Task task) { final int taskId = task.mTaskId; // Check if the parent info is different from the last reported parent info. - final Configuration taskConfig = task.getConfiguration(); - final Configuration lastParentConfig = mLastSentTaskFragmentParentConfigs.get(taskId); - if (configurationsAreEqualForOrganizer(taskConfig, lastParentConfig) - && taskConfig.windowConfiguration.getWindowingMode() - == lastParentConfig.windowConfiguration.getWindowingMode()) { + final TaskFragmentParentInfo parentInfo = task.getTaskFragmentParentInfo(); + final TaskFragmentParentInfo lastParentInfo = mLastSentTaskFragmentParentInfos + .get(taskId); + final Configuration lastParentConfig = lastParentInfo != null + ? lastParentInfo.getConfiguration() : null; + if (parentInfo.equalsForTaskFragmentOrganizer(lastParentInfo) + && configurationsAreEqualForOrganizer(parentInfo.getConfiguration(), + lastParentConfig)) { return null; } ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment parent info changed name=%s parentTaskId=%d", task.getName(), taskId); - mLastSentTaskFragmentParentConfigs.put(taskId, new Configuration(taskConfig)); + mLastSentTaskFragmentParentInfos.put(taskId, new TaskFragmentParentInfo(parentInfo)); return new TaskFragmentTransaction.Change(TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED) .setTaskId(taskId) - .setTaskConfiguration(taskConfig); + .setTaskFragmentParentInfo(parentInfo); } @NonNull diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java index 9bdf750767b3d..61cf8cc76d83b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.view.Display.DEFAULT_DISPLAY; import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_OP_TYPE; import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_THROWABLE; import static android.window.TaskFragmentOrganizer.getTransitionType; @@ -76,6 +77,7 @@ import android.window.TaskFragmentCreationParams; import android.window.TaskFragmentInfo; import android.window.TaskFragmentOrganizer; import android.window.TaskFragmentOrganizerToken; +import android.window.TaskFragmentParentInfo; import android.window.TaskFragmentTransaction; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; @@ -271,7 +273,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { @Test public void testOnTaskFragmentParentInfoChanged() { setupMockParent(mTaskFragment, mTask); - mTask.getConfiguration().smallestScreenWidthDp = 10; + mTask.getTaskFragmentParentInfo().getConfiguration().smallestScreenWidthDp = 10; mController.onTaskFragmentAppeared( mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); @@ -295,7 +297,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { // Trigger callback if the size is changed. clearInvocations(mOrganizer); - mTask.getConfiguration().smallestScreenWidthDp = 100; + mTask.getTaskFragmentParentInfo().getConfiguration().smallestScreenWidthDp = 100; mController.onTaskFragmentInfoChanged( mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); @@ -304,7 +306,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { // Trigger callback if the windowing mode is changed. clearInvocations(mOrganizer); - mTask.getConfiguration().windowConfiguration.setWindowingMode(WINDOWING_MODE_PINNED); + mTask.getTaskFragmentParentInfo().getConfiguration().windowConfiguration + .setWindowingMode(WINDOWING_MODE_PINNED); mController.onTaskFragmentInfoChanged( mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); @@ -1268,7 +1271,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { final TaskFragmentTransaction.Change change = changes.get(0); assertEquals(TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED, change.getType()); assertEquals(task.mTaskId, change.getTaskId()); - assertEquals(task.getConfiguration(), change.getTaskConfiguration()); + assertEquals(task.getTaskFragmentParentInfo(), change.getTaskFragmentParentInfo()); } /** Asserts that there will be a transaction for TaskFragment error. */ @@ -1316,8 +1319,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { /** Setups the mock Task as the parent of the given TaskFragment. */ private static void setupMockParent(TaskFragment taskFragment, Task mockParent) { doReturn(mockParent).when(taskFragment).getTask(); - final Configuration taskConfig = new Configuration(); - doReturn(taskConfig).when(mockParent).getConfiguration(); + doReturn(new TaskFragmentParentInfo(new Configuration(), DEFAULT_DISPLAY, true)) + .when(mockParent).getTaskFragmentParentInfo(); // Task needs to be visible mockParent.lastActiveTime = 100;