Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c9120521 authored by Vinit Nayak's avatar Vinit Nayak Committed by Android (Google) Code Review
Browse files

Merge "Refactor SplitSelectStateController to add testing" into tm-qpr-dev

parents 3d103192 4e3636e8
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -235,7 +235,8 @@ public class QuickstepLauncher extends Launcher {
        RecentsView overviewPanel = getOverviewPanel();
        mSplitSelectStateController =
                new SplitSelectStateController(this, mHandler, getStateManager(),
                        getDepthController(), getStatsLogManager());
                        getDepthController(), getStatsLogManager(),
                        SystemUiProxy.INSTANCE.get(this), RecentsModel.INSTANCE.get(this));
        overviewPanel.init(mActionsView, mSplitSelectStateController);
        mSplitWithKeyboardShortcutController = new SplitWithKeyboardShortcutController(this,
                mSplitSelectStateController);
+2 −1
Original line number Diff line number Diff line
@@ -134,7 +134,8 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {

        SplitSelectStateController controller =
                new SplitSelectStateController(this, mHandler, getStateManager(),
                        /* depthController */ null, getStatsLogManager());
                         null /* depthController */, getStatsLogManager(),
                        SystemUiProxy.INSTANCE.get(this), RecentsModel.INSTANCE.get(this));
        mDragLayer.recreateControllers();
        mFallbackRecentsView.init(mActionsView, controller);

+4 −3
Original line number Diff line number Diff line
@@ -107,14 +107,15 @@ public class SplitSelectStateController {
    private FloatingTaskView mFirstFloatingTaskView;

    public SplitSelectStateController(Context context, Handler handler, StateManager stateManager,
            DepthController depthController, StatsLogManager statsLogManager) {
            DepthController depthController, StatsLogManager statsLogManager,
            SystemUiProxy systemUiProxy, RecentsModel recentsModel) {
        mContext = context;
        mHandler = handler;
        mStatsLogManager = statsLogManager;
        mSystemUiProxy = SystemUiProxy.INSTANCE.get(mContext);
        mSystemUiProxy = systemUiProxy;
        mStateManager = stateManager;
        mDepthController = depthController;
        mRecentTasksModel = RecentsModel.INSTANCE.get(context);
        mRecentTasksModel = recentsModel;
    }

    /**
+212 −0
Original line number Diff line number Diff line
/*
 *  Copyright (C) 2023 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.quickstep.util

import android.app.ActivityManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.graphics.Rect
import android.os.Handler
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.launcher3.LauncherState
import com.android.launcher3.logging.StatsLogManager
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.statehandlers.DepthController
import com.android.launcher3.statemanager.StateManager
import com.android.launcher3.util.SplitConfigurationOptions
import com.android.launcher3.util.withArgCaptor
import com.android.quickstep.RecentsModel
import com.android.quickstep.SystemUiProxy
import com.android.systemui.shared.recents.model.Task
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import java.util.ArrayList
import java.util.function.Consumer


@RunWith(AndroidJUnit4::class)
class SplitSelectStateControllerTest {

    @Mock lateinit var systemUiProxy: SystemUiProxy
    @Mock lateinit var depthController: DepthController
    @Mock lateinit var statsLogManager: StatsLogManager
    @Mock lateinit var stateManager: StateManager<LauncherState>
    @Mock lateinit var handler: Handler
    @Mock lateinit var context: Context
    @Mock lateinit var recentsModel: RecentsModel

    lateinit var splitSelectStateController: SplitSelectStateController

    @Before
    fun setup() {
        MockitoAnnotations.initMocks(this)
        splitSelectStateController = SplitSelectStateController(context, handler,
                stateManager, depthController, statsLogManager, systemUiProxy, recentsModel)
    }

    @Test
    fun activeTasks_noMatchingTasks() {
        val groupTask1 = generateGroupTask(
                ComponentName("pomegranate", "juice"),
                ComponentName("pumpkin", "pie"))
        val groupTask2 = generateGroupTask(
                ComponentName("hotdog", "juice"),
                ComponentName("personal", "computer"))
        val tasks: ArrayList<GroupTask> = ArrayList()
        tasks.add(groupTask1)
        tasks.add(groupTask2)

        // Assertions happen in the callback we get from what we pass into
        // #findLastActiveTaskAndRunCallback
        val taskConsumer = Consumer<Task> {
            assertNull("No tasks should have matched", it /*task*/)
        }

        // Capture callback from recentsModel#getTasks()
        val consumer = withArgCaptor<Consumer<ArrayList<GroupTask>>> {
            splitSelectStateController.findLastActiveTaskAndRunCallback(
                    ComponentName("no", "match"), taskConsumer)
            verify(recentsModel).getTasks(capture())
        }

        // Send our mocked tasks
        consumer.accept(tasks)
    }

    @Test
    fun activeTasks_singleMatchingTask() {
        val matchingPackage = "hotdog"
        val matchingClass = "juice"
        val groupTask1 = generateGroupTask(
                ComponentName(matchingPackage, matchingClass),
                ComponentName("pomegranate", "juice"))
        val groupTask2 = generateGroupTask(
                ComponentName("pumpkin", "pie"),
                ComponentName("personal", "computer"))
        val tasks: ArrayList<GroupTask> = ArrayList()
        tasks.add(groupTask1)
        tasks.add(groupTask2)

        // Assertions happen in the callback we get from what we pass into
        // #findLastActiveTaskAndRunCallback
        val taskConsumer = Consumer<Task> {
            assertEquals("ComponentName package mismatched",
                    it.key.baseIntent.component.packageName, matchingPackage)
            assertEquals("ComponentName class mismatched",
                    it.key.baseIntent.component.className, matchingClass)
            assertEquals(it, groupTask1.task1)
        }

        // Capture callback from recentsModel#getTasks()
        val consumer = withArgCaptor<Consumer<ArrayList<GroupTask>>> {
            splitSelectStateController.findLastActiveTaskAndRunCallback(
                    ComponentName(matchingPackage, matchingClass), taskConsumer)
            verify(recentsModel).getTasks(capture())
        }

        // Send our mocked tasks
        consumer.accept(tasks)
    }

    @Test
    fun activeTasks_multipleMatchMostRecentTask() {
        val matchingPackage = "hotdog"
        val matchingClass = "juice"
        val groupTask1 = generateGroupTask(
                ComponentName(matchingPackage, matchingClass),
                ComponentName("pumpkin", "pie"))
        val groupTask2 = generateGroupTask(
                ComponentName("pomegranate", "juice"),
                ComponentName(matchingPackage, matchingClass))
        val tasks: ArrayList<GroupTask> = ArrayList()
        tasks.add(groupTask2)
        tasks.add(groupTask1)

        // Assertions happen in the callback we get from what we pass into
        // #findLastActiveTaskAndRunCallback
        val taskConsumer = Consumer<Task> {
            assertEquals("ComponentName package mismatched",
                    it.key.baseIntent.component.packageName, matchingPackage)
            assertEquals("ComponentName class mismatched",
                    it.key.baseIntent.component.className, matchingClass)
            assertEquals(it, groupTask2.task2)
        }

        // Capture callback from recentsModel#getTasks()
        val consumer = withArgCaptor<Consumer<ArrayList<GroupTask>>> {
            splitSelectStateController.findLastActiveTaskAndRunCallback(
                    ComponentName(matchingPackage, matchingClass), taskConsumer)
            verify(recentsModel).getTasks(capture())
        }

        // Send our mocked tasks
        consumer.accept(tasks)
    }

    @Test
    fun setInitialApp_withTaskId() {
        splitSelectStateController.setInitialTaskSelect(null /*intent*/,
                -1 /*stagePosition*/, ItemInfo(), null /*splitEvent*/, 10 /*alreadyRunningTask*/)
        assertTrue(splitSelectStateController.isSplitSelectActive)
    }

    @Test
    fun setInitialApp_withIntent() {
        splitSelectStateController.setInitialTaskSelect(Intent() /*intent*/,
                -1 /*stagePosition*/, ItemInfo(), null /*splitEvent*/, -1 /*alreadyRunningTask*/)
        assertTrue(splitSelectStateController.isSplitSelectActive)
    }

    @Test
    fun resetAfterInitial() {
        splitSelectStateController.setInitialTaskSelect(Intent() /*intent*/,
                -1 /*stagePosition*/, ItemInfo(), null /*splitEvent*/,
                -1)
        splitSelectStateController.resetState()
        assertFalse(splitSelectStateController.isSplitSelectActive)
    }

    private fun generateGroupTask(task1ComponentName: ComponentName,
                                  task2ComponentName: ComponentName): GroupTask {
        val task1 = Task()
        var taskInfo = ActivityManager.RunningTaskInfo()
        var intent = Intent()
        intent.component = task1ComponentName
        taskInfo.baseIntent = intent
        task1.key = Task.TaskKey(taskInfo)

        val task2 = Task()
        taskInfo = ActivityManager.RunningTaskInfo()
        intent = Intent()
        intent.component = task2ComponentName
        taskInfo.baseIntent = intent
        task2.key = Task.TaskKey(taskInfo)
        return GroupTask(task1, task2, SplitConfigurationOptions.SplitBounds(
                Rect(), Rect(), -1, -1
        ))
    }
}
 No newline at end of file