Fixed split in Desktop windowing

When desktop windowing is enable and split is selected, during second app selection apps' scroll was far off on left. There were several things needed to fix this :
1. Hide DesktopTaskView during split select mode by changing splitAlpha
2. Fix min/max scroll calculation by excluding DesktopTaskView in split select mode
3. Exclude DesktopTaskView in updateGridProperties row length calcualtion

Testing: Manually needed to test multiple scenarios
1. Split focused task.
2. Split Even/Odd tasks in top and bottom rows.
3. Split tasks from home screen
4. Split and rotate screen.
5. Split from app icon chip

Test: SplitSelectStateControllerTest, Manual
BUG: 330342294
FIX: 330342294
Flag: com.android.launcher3.enable_large_desktop_windowing_tile
Change-Id: I789873100f42896c9ed3084accb0f6970abcba0c
This commit is contained in:
vinayjoglekar
2024-09-23 09:52:04 +01:00
parent 2b1208e803
commit 562ab4d188
7 changed files with 129 additions and 60 deletions
@@ -155,6 +155,9 @@ public final class RecentsViewStateController extends
0,
timings.getGridSlideSecondaryInterpolator());
mRecentsView.handleDesktopTaskInSplitSelectState(builder,
timings.getDesktopTaskFadeInterpolator());
if (!animate) {
AnimatorSet as = builder.buildAnim();
as.start();
@@ -73,9 +73,21 @@ class RecentsViewUtils {
* Returns the first TaskView that should be displayed as a large tile.
*
* @param taskViews List of [TaskView]s
* @param splitSelectActive current split state
*/
fun getFirstLargeTaskView(taskViews: Iterable<TaskView>): TaskView? =
taskViews.firstOrNull { it.isLargeTile }
fun getFirstLargeTaskView(
taskViews: MutableIterable<TaskView>,
splitSelectActive: Boolean,
): TaskView? =
taskViews.firstOrNull { it.isLargeTile && !(splitSelectActive && it is DesktopTaskView) }
/**
* Returns the first TaskView that is not large
*
* @param taskViews List of [TaskView]s
*/
fun getFirstSmallTaskView(taskViews: MutableIterable<TaskView>): TaskView? =
taskViews.firstOrNull { !it.isLargeTile }
/** Returns the last TaskView that should be displayed as a large tile. */
fun getLastLargeTaskView(taskViews: Iterable<TaskView>): TaskView? =
@@ -105,6 +105,10 @@ public interface SplitAnimationTimings {
default Interpolator getGridSlidePrimaryInterpolator() { return LINEAR; }
default Interpolator getGridSlideSecondaryInterpolator() { return LINEAR; }
default Interpolator getDesktopTaskFadeInterpolator() {
return LINEAR;
}
// Defaults for HomeToSplit
default float getScrimFadeInStartOffset() { return 0; }
default float getScrimFadeInEndOffset() { return 0; }
@@ -743,6 +743,7 @@ public class SplitSelectStateController {
*/
public void resetState() {
mSplitSelectDataHolder.resetState();
mContainer.<RecentsView>getOverviewPanel().resetDesktopTaskFromSplitSelectState();
dispatchOnSplitSelectionExit();
mRecentsAnimationRunning = false;
mLaunchingTaskView = null;
@@ -3140,7 +3140,7 @@ public abstract class RecentsView<
// Horizontal grid translation for each task
float[] gridTranslations = new float[taskCount];
int focusedTaskIndex = Integer.MAX_VALUE;
int lastLargeTaskIndex = Integer.MAX_VALUE;
Set<Integer> largeTasksIndices = new HashSet<>();
int focusedTaskShift = 0;
int largeTaskWidthAndSpacing = 0;
@@ -3163,8 +3163,12 @@ public abstract class RecentsView<
boolean isLargeTile = taskView.isLargeTile();
if (isLargeTile) {
topRowWidth += taskWidthAndSpacing;
bottomRowWidth += taskWidthAndSpacing;
// DesktopTaskView`s are hidden during split select state, so we shouldn't count
// them when calculating row width.
if (!(taskView instanceof DesktopTaskView && isSplitSelectionActive())) {
topRowWidth += taskWidthAndSpacing;
bottomRowWidth += taskWidthAndSpacing;
}
gridTranslations[i] += focusedTaskShift;
gridTranslations[i] += mIsRtl ? taskWidthAndSpacing : -taskWidthAndSpacing;
@@ -3172,9 +3176,7 @@ public abstract class RecentsView<
taskView.setGridTranslationY((mLastComputedTaskSize.height() + taskTopMargin
- taskView.getLayoutParams().height) / 2f);
if (taskView.getTaskViewId() == mFocusedTaskViewId) {
focusedTaskIndex = i;
}
lastLargeTaskIndex = i;
largeTasksIndices.add(i);
largeTaskWidthAndSpacing = taskWidthAndSpacing;
@@ -3183,8 +3185,8 @@ public abstract class RecentsView<
snappedTaskRowWidth = taskWidthAndSpacing;
}
} else {
if (i > focusedTaskIndex) {
// For tasks after the focused task, shift by focused task's width and spacing.
if (i > lastLargeTaskIndex) {
// For tasks after the last large task, shift by large task's width and spacing.
gridTranslations[i] +=
mIsRtl ? largeTaskWidthAndSpacing : -largeTaskWidthAndSpacing;
} else {
@@ -5023,6 +5025,35 @@ public abstract class RecentsView<
splitSelectSource.splitEvent, splitSelectSource.alreadyRunningTaskId);
}
/**
* Animate DesktopTaskView(s) to hide in split select
*/
public void handleDesktopTaskInSplitSelectState(PendingAnimation builder,
Interpolator deskTopFadeInterPolator) {
if (enableLargeDesktopWindowingTile()) {
for (TaskView taskView : getTaskViews()) {
if (taskView instanceof DesktopTaskView) {
builder.addFloat(taskView.getSplitAlphaProperty(),
MULTI_PROPERTY_VALUE, 1f, 0f,
deskTopFadeInterPolator);
}
}
}
}
/**
* While exiting from split mode, show all existing DesktopTaskViews.
*/
public void resetDesktopTaskFromSplitSelectState() {
if (enableLargeDesktopWindowingTile()) {
for (TaskView taskView : getTaskViews()) {
if (taskView instanceof DesktopTaskView) {
taskView.setSplitAlpha(1f);
}
}
}
}
/**
* Modifies a PendingAnimation with the animations for entering split staging
*/
@@ -5857,11 +5888,12 @@ public abstract class RecentsView<
if (mShowAsGridLastOnLayout) {
// For grid Overview, it always start if a large tile (focused task or desktop task) if
// they exist, otherwise it start with the first task.
TaskView firstLargeTaskView = mUtils.getFirstLargeTaskView(getTaskViews());
TaskView firstLargeTaskView = mUtils.getFirstLargeTaskView(getTaskViews(),
isSplitSelectionActive());
if (firstLargeTaskView != null) {
firstView = firstLargeTaskView;
} else {
firstView = getTaskViewAt(0);
firstView = mUtils.getFirstSmallTaskView(getTaskViews());
}
} else {
firstView = mUtils.getFirstTaskViewInCarousel(
@@ -402,6 +402,15 @@ constructor(
}
get() = taskViewAlpha.get(ALPHA_INDEX_ATTACH).value
var splitAlpha
set(value) {
splitAlphaProperty.value = value
}
get() = splitAlphaProperty.value
val splitAlphaProperty: MultiPropertyFactory<View>.MultiProperty
get() = taskViewAlpha.get(ALPHA_INDEX_SPLIT)
protected var shouldShowScreenshot = false
get() = !isRunningTask || field
private set
@@ -606,6 +615,7 @@ constructor(
override fun onRecycle() {
resetPersistentViewTransforms()
attachAlpha = 1f
splitAlpha = 1f
// Clear any references to the thumbnail (it will be re-read either from the cache or the
// system on next bind)
if (!enableRefactorTaskThumbnail()) {
@@ -1687,8 +1697,9 @@ constructor(
private const val ALPHA_INDEX_STABLE = 0
private const val ALPHA_INDEX_ATTACH = 1
private const val ALPHA_INDEX_SPLIT = 2
private const val NUM_ALPHA_CHANNELS = 2
private const val NUM_ALPHA_CHANNELS = 3
/** The maximum amount that a task view can be scrimmed, dimmed or tinted. */
const val MAX_PAGE_SCRIM_ALPHA = 0.4f
@@ -36,6 +36,7 @@ import com.android.launcher3.util.SplitConfigurationOptions
import com.android.quickstep.RecentsModel
import com.android.quickstep.SystemUiProxy
import com.android.quickstep.util.SplitSelectStateController.SplitFromDesktopController
import com.android.quickstep.views.RecentsView
import com.android.quickstep.views.RecentsViewContainer
import com.android.systemui.shared.recents.model.Task
import com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_50_50
@@ -50,6 +51,7 @@ import org.mockito.Mockito.any
import org.mockito.Mockito.`when`
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.mock
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import java.util.function.Consumer
@@ -66,6 +68,7 @@ class SplitSelectStateControllerTest {
private val recentsModel: RecentsModel = mock()
private val pendingIntent: PendingIntent = mock()
private val splitFromDesktopController: SplitFromDesktopController = mock()
private val recentsView: RecentsView<*, *> = mock()
private lateinit var splitSelectStateController: SplitSelectStateController
@@ -73,6 +76,7 @@ class SplitSelectStateControllerTest {
private val nonPrimaryUserHandle = UserHandle(ActivityManager.RunningTaskInfo().userId + 10)
private var taskIdCounter = 0
private fun getUniqueId(): Int {
return ++taskIdCounter
}
@@ -90,7 +94,7 @@ class SplitSelectStateControllerTest {
statsLogManager,
systemUiProxy,
recentsModel,
null /*activityBackCallback*/
null, /*activityBackCallback*/
)
}
@@ -100,12 +104,12 @@ class SplitSelectStateControllerTest {
val groupTask1 =
generateGroupTask(
ComponentName("pomegranate", "juice"),
ComponentName("pumpkin", "pie")
ComponentName("pumpkin", "pie"),
)
val groupTask2 =
generateGroupTask(
ComponentName("hotdog", "juice"),
ComponentName("personal", "computer")
ComponentName("personal", "computer"),
)
val tasks: ArrayList<GroupTask> = ArrayList()
tasks.add(groupTask1)
@@ -122,7 +126,7 @@ class SplitSelectStateControllerTest {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(nonMatchingComponent),
false /* findExactPairMatch */,
taskConsumer
taskConsumer,
)
verify(recentsModel).getTasks(capture())
}
@@ -141,12 +145,12 @@ class SplitSelectStateControllerTest {
val groupTask1 =
generateGroupTask(
ComponentName(matchingPackage, matchingClass),
ComponentName("pomegranate", "juice")
ComponentName("pomegranate", "juice"),
)
val groupTask2 =
generateGroupTask(
ComponentName("pumpkin", "pie"),
ComponentName("personal", "computer")
ComponentName("personal", "computer"),
)
val tasks: ArrayList<GroupTask> = ArrayList()
tasks.add(groupTask1)
@@ -159,12 +163,12 @@ class SplitSelectStateControllerTest {
assertEquals(
"ComponentName package mismatched",
it[0].key.baseIntent.component?.packageName,
matchingPackage
matchingPackage,
)
assertEquals(
"ComponentName class mismatched",
it[0].key.baseIntent.component?.className,
matchingClass
matchingClass,
)
assertEquals(it[0], groupTask1.task1)
}
@@ -175,7 +179,7 @@ class SplitSelectStateControllerTest {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(matchingComponent),
false /* findExactPairMatch */,
taskConsumer
taskConsumer,
)
verify(recentsModel).getTasks(capture())
}
@@ -194,12 +198,12 @@ class SplitSelectStateControllerTest {
val groupTask1 =
generateGroupTask(
ComponentName(matchingPackage, matchingClass),
ComponentName("pomegranate", "juice")
ComponentName("pomegranate", "juice"),
)
val groupTask2 =
generateGroupTask(
ComponentName("pumpkin", "pie"),
ComponentName("personal", "computer")
ComponentName("personal", "computer"),
)
val tasks: ArrayList<GroupTask> = ArrayList()
tasks.add(groupTask1)
@@ -216,7 +220,7 @@ class SplitSelectStateControllerTest {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(nonPrimaryUserComponent),
false /* findExactPairMatch */,
taskConsumer
taskConsumer,
)
verify(recentsModel).getTasks(capture())
}
@@ -237,12 +241,12 @@ class SplitSelectStateControllerTest {
ComponentName(matchingPackage, matchingClass),
nonPrimaryUserHandle,
ComponentName("pomegranate", "juice"),
nonPrimaryUserHandle
nonPrimaryUserHandle,
)
val groupTask2 =
generateGroupTask(
ComponentName("pumpkin", "pie"),
ComponentName("personal", "computer")
ComponentName("personal", "computer"),
)
val tasks: ArrayList<GroupTask> = ArrayList()
tasks.add(groupTask1)
@@ -255,12 +259,12 @@ class SplitSelectStateControllerTest {
assertEquals(
"ComponentName package mismatched",
it[0].key.baseIntent.component?.packageName,
matchingPackage
matchingPackage,
)
assertEquals(
"ComponentName class mismatched",
it[0].key.baseIntent.component?.className,
matchingClass
matchingClass,
)
assertEquals("userId mismatched", it[0].key.userId, nonPrimaryUserHandle.identifier)
assertEquals(it[0], groupTask1.task1)
@@ -272,7 +276,7 @@ class SplitSelectStateControllerTest {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(nonPrimaryUserComponent),
false /* findExactPairMatch */,
taskConsumer
taskConsumer,
)
verify(recentsModel).getTasks(capture())
}
@@ -291,12 +295,12 @@ class SplitSelectStateControllerTest {
val groupTask1 =
generateGroupTask(
ComponentName(matchingPackage, matchingClass),
ComponentName("pumpkin", "pie")
ComponentName("pumpkin", "pie"),
)
val groupTask2 =
generateGroupTask(
ComponentName("pomegranate", "juice"),
ComponentName(matchingPackage, matchingClass)
ComponentName(matchingPackage, matchingClass),
)
val tasks: ArrayList<GroupTask> = ArrayList()
tasks.add(groupTask2)
@@ -309,12 +313,12 @@ class SplitSelectStateControllerTest {
assertEquals(
"ComponentName package mismatched",
it[0].key.baseIntent.component?.packageName,
matchingPackage
matchingPackage,
)
assertEquals(
"ComponentName class mismatched",
it[0].key.baseIntent.component?.className,
matchingClass
matchingClass,
)
assertEquals(it[0], groupTask1.task1)
}
@@ -325,7 +329,7 @@ class SplitSelectStateControllerTest {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(matchingComponent),
false /* findExactPairMatch */,
taskConsumer
taskConsumer,
)
verify(recentsModel).getTasks(capture())
}
@@ -348,7 +352,7 @@ class SplitSelectStateControllerTest {
val groupTask2 =
generateGroupTask(
ComponentName("pomegranate", "juice"),
ComponentName(matchingPackage, matchingClass)
ComponentName(matchingPackage, matchingClass),
)
val tasks: ArrayList<GroupTask> = ArrayList()
tasks.add(groupTask2)
@@ -363,12 +367,12 @@ class SplitSelectStateControllerTest {
assertEquals(
"ComponentName package mismatched",
it[1].key.baseIntent.component?.packageName,
matchingPackage
matchingPackage,
)
assertEquals(
"ComponentName class mismatched",
it[1].key.baseIntent.component?.className,
matchingClass
matchingClass,
)
assertEquals(it[1], groupTask2.task2)
}
@@ -379,7 +383,7 @@ class SplitSelectStateControllerTest {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(nonMatchingComponent, matchingComponent),
false /* findExactPairMatch */,
taskConsumer
taskConsumer,
)
verify(recentsModel).getTasks(capture())
}
@@ -401,7 +405,7 @@ class SplitSelectStateControllerTest {
val groupTask2 =
generateGroupTask(
ComponentName("pomegranate", "juice"),
ComponentName(matchingPackage, matchingClass)
ComponentName(matchingPackage, matchingClass),
)
val tasks: ArrayList<GroupTask> = ArrayList()
tasks.add(groupTask2)
@@ -415,12 +419,12 @@ class SplitSelectStateControllerTest {
assertEquals(
"ComponentName package mismatched",
it[0].key.baseIntent.component?.packageName,
matchingPackage
matchingPackage,
)
assertEquals(
"ComponentName class mismatched",
it[0].key.baseIntent.component?.className,
matchingClass
matchingClass,
)
assertEquals(it[0], groupTask2.task2)
assertNull("No tasks should have matched", it[1] /*task*/)
@@ -432,7 +436,7 @@ class SplitSelectStateControllerTest {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(matchingComponent, matchingComponent),
false /* findExactPairMatch */,
taskConsumer
taskConsumer,
)
verify(recentsModel).getTasks(capture())
}
@@ -452,12 +456,12 @@ class SplitSelectStateControllerTest {
val groupTask1 =
generateGroupTask(
ComponentName(matchingPackage, matchingClass),
ComponentName("pumpkin", "pie")
ComponentName("pumpkin", "pie"),
)
val groupTask2 =
generateGroupTask(
ComponentName("pomegranate", "juice"),
ComponentName(matchingPackage, matchingClass)
ComponentName(matchingPackage, matchingClass),
)
val tasks: ArrayList<GroupTask> = ArrayList()
tasks.add(groupTask2)
@@ -471,23 +475,23 @@ class SplitSelectStateControllerTest {
assertEquals(
"ComponentName package mismatched",
it[0].key.baseIntent.component?.packageName,
matchingPackage
matchingPackage,
)
assertEquals(
"ComponentName class mismatched",
it[0].key.baseIntent.component?.className,
matchingClass
matchingClass,
)
assertEquals(it[0], groupTask1.task1)
assertEquals(
"ComponentName package mismatched",
it[1].key.baseIntent.component?.packageName,
matchingPackage
matchingPackage,
)
assertEquals(
"ComponentName class mismatched",
it[1].key.baseIntent.component?.className,
matchingClass
matchingClass,
)
assertEquals(it[1], groupTask2.task2)
}
@@ -498,7 +502,7 @@ class SplitSelectStateControllerTest {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(matchingComponent, matchingComponent),
false /* findExactPairMatch */,
taskConsumer
taskConsumer,
)
verify(recentsModel).getTasks(capture())
}
@@ -524,12 +528,12 @@ class SplitSelectStateControllerTest {
val groupTask2 =
generateGroupTask(
ComponentName(matchingPackage2, matchingClass2),
ComponentName(matchingPackage, matchingClass)
ComponentName(matchingPackage, matchingClass),
)
val groupTask3 =
generateGroupTask(
ComponentName("hotdog", "pie"),
ComponentName(matchingPackage, matchingClass)
ComponentName(matchingPackage, matchingClass),
)
val tasks: ArrayList<GroupTask> = ArrayList()
tasks.add(groupTask3)
@@ -550,7 +554,7 @@ class SplitSelectStateControllerTest {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(matchingComponent2, matchingComponent),
true /* findExactPairMatch */,
taskConsumer
taskConsumer,
)
verify(recentsModel).getTasks(capture())
}
@@ -567,7 +571,7 @@ class SplitSelectStateControllerTest {
-1 /*stagePosition*/,
ItemInfo(),
null /*splitEvent*/,
10 /*alreadyRunningTask*/
10, /*alreadyRunningTask*/
)
assertTrue(splitSelectStateController.isSplitSelectActive)
}
@@ -579,21 +583,23 @@ class SplitSelectStateControllerTest {
-1 /*stagePosition*/,
ItemInfo(),
null /*splitEvent*/,
-1 /*alreadyRunningTask*/
-1, /*alreadyRunningTask*/
)
assertTrue(splitSelectStateController.isSplitSelectActive)
}
@Test
fun resetAfterInitial() {
whenever(context.getOverviewPanel<RecentsView<*, *>>()).thenReturn(recentsView)
splitSelectStateController.setInitialTaskSelect(
Intent() /*intent*/,
-1 /*stagePosition*/,
ItemInfo(),
null /*splitEvent*/,
-1
-1,
)
splitSelectStateController.resetState()
verify(recentsView, times(1)).resetDesktopTaskFromSplitSelectState()
assertFalse(splitSelectStateController.isSplitSelectActive)
}
@@ -622,7 +628,7 @@ class SplitSelectStateControllerTest {
// Generate GroupTask with default userId.
private fun generateGroupTask(
task1ComponentName: ComponentName,
task2ComponentName: ComponentName
task2ComponentName: ComponentName,
): GroupTask {
val task1 = Task()
var taskInfo = ActivityManager.RunningTaskInfo()
@@ -642,7 +648,7 @@ class SplitSelectStateControllerTest {
return GroupTask(
task1,
task2,
SplitConfigurationOptions.SplitBounds(Rect(), Rect(), -1, -1, SNAP_TO_2_50_50)
SplitConfigurationOptions.SplitBounds(Rect(), Rect(), -1, -1, SNAP_TO_2_50_50),
)
}
@@ -651,7 +657,7 @@ class SplitSelectStateControllerTest {
task1ComponentName: ComponentName,
userHandle1: UserHandle,
task2ComponentName: ComponentName,
userHandle2: UserHandle
userHandle2: UserHandle,
): GroupTask {
val task1 = Task()
var taskInfo = ActivityManager.RunningTaskInfo()
@@ -674,7 +680,7 @@ class SplitSelectStateControllerTest {
return GroupTask(
task1,
task2,
SplitConfigurationOptions.SplitBounds(Rect(), Rect(), -1, -1, SNAP_TO_2_50_50)
SplitConfigurationOptions.SplitBounds(Rect(), Rect(), -1, -1, SNAP_TO_2_50_50),
)
}
}