Enable tests which do not require any modification
Fix: 329052420 Flag: NA Test: Presubmits + :NexusLauncher:testGoogleWithQuickstepDebugUnitTest Change-Id: I27e847c923076e4e978fd7359c9c62745d4f5f0a
This commit is contained in:
+132
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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.launcher3.model;
|
||||
|
||||
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
|
||||
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS;
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.prediction.AppTarget;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.launcher3.logger.LauncherAtom;
|
||||
import com.android.launcher3.model.data.AppInfo;
|
||||
import com.android.launcher3.pm.UserCache;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
|
||||
import com.android.launcher3.util.UserIconInfo;
|
||||
import com.android.systemui.shared.system.SysUiStatsLog;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AppEventProducerTest {
|
||||
|
||||
private static final UserHandle MAIN_HANDLE = Process.myUserHandle();
|
||||
private static final UserHandle PRIVATE_HANDLE = new UserHandle(11);
|
||||
|
||||
private static final UserIconInfo MAIN_ICON_INFO =
|
||||
new UserIconInfo(MAIN_HANDLE, UserIconInfo.TYPE_MAIN);
|
||||
private static final UserIconInfo PRIVATE_ICON_INFO =
|
||||
new UserIconInfo(PRIVATE_HANDLE, UserIconInfo.TYPE_PRIVATE);
|
||||
|
||||
private SandboxContext mContext;
|
||||
private AppEventProducer mAppEventProducer;
|
||||
@Mock
|
||||
private UserCache mUserCache;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = new SandboxContext(getApplicationContext());
|
||||
mContext.putObject(UserCache.INSTANCE, mUserCache);
|
||||
mAppEventProducer = new AppEventProducer(mContext, null);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
mContext.onDestroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildAppTarget_containsCorrectUser() {
|
||||
when(mUserCache.getUserProfiles())
|
||||
.thenReturn(Arrays.asList(MAIN_HANDLE, PRIVATE_HANDLE));
|
||||
when(mUserCache.getUserInfo(any(UserHandle.class)))
|
||||
.thenReturn(MAIN_ICON_INFO, PRIVATE_ICON_INFO);
|
||||
ComponentName gmailComponentName = new ComponentName(mContext,
|
||||
"com.android.launcher3.tests.Activity" + "Gmail");
|
||||
AppInfo gmailAppInfo = new
|
||||
AppInfo(gmailComponentName, "Gmail", MAIN_HANDLE, new Intent());
|
||||
gmailAppInfo.container = CONTAINER_ALL_APPS;
|
||||
gmailAppInfo.itemType = ITEM_TYPE_APPLICATION;
|
||||
|
||||
AppTarget gmailTarget = mAppEventProducer
|
||||
.toAppTarget(buildItemInfoProtoForAppInfo(gmailAppInfo));
|
||||
|
||||
assert gmailTarget != null;
|
||||
assertEquals(gmailTarget.getUser(), MAIN_HANDLE);
|
||||
|
||||
when(mUserCache.getUserInfo(any(UserHandle.class)))
|
||||
.thenReturn(MAIN_ICON_INFO, PRIVATE_ICON_INFO);
|
||||
AppInfo gmailAppInfoPrivate = new
|
||||
AppInfo(gmailComponentName, "Gmail", PRIVATE_HANDLE, new Intent());
|
||||
gmailAppInfoPrivate.container = CONTAINER_ALL_APPS;
|
||||
gmailAppInfoPrivate.itemType = ITEM_TYPE_APPLICATION;
|
||||
|
||||
AppTarget gmailPrivateTarget = mAppEventProducer
|
||||
.toAppTarget(buildItemInfoProtoForAppInfo(gmailAppInfoPrivate));
|
||||
|
||||
assert gmailPrivateTarget != null;
|
||||
assertEquals(gmailPrivateTarget.getUser(), PRIVATE_HANDLE);
|
||||
}
|
||||
|
||||
private LauncherAtom.ItemInfo buildItemInfoProtoForAppInfo(AppInfo appInfo) {
|
||||
LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
|
||||
if (appInfo.user.equals(PRIVATE_HANDLE)) {
|
||||
itemBuilder.setUserType(SysUiStatsLog.LAUNCHER_UICHANGED__USER_TYPE__TYPE_PRIVATE);
|
||||
} else {
|
||||
itemBuilder.setUserType(SysUiStatsLog.LAUNCHER_UICHANGED__USER_TYPE__TYPE_MAIN);
|
||||
}
|
||||
itemBuilder.setApplication(LauncherAtom.Application.newBuilder()
|
||||
.setComponentName(appInfo.componentName.flattenToShortString())
|
||||
.setPackageName(appInfo.componentName.getPackageName()));
|
||||
itemBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
|
||||
.setAllAppsContainer(LauncherAtom.AllAppsContainer.getDefaultInstance())
|
||||
.build());
|
||||
return itemBuilder.build();
|
||||
}
|
||||
}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
package com.android.launcher3.taskbar;
|
||||
|
||||
import static android.view.MotionEvent.ACTION_DOWN;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class RecentsHitboxExtenderTest {
|
||||
|
||||
private static final int TASKBAR_OFFSET_Y = 35;
|
||||
private static final int BUTTON_WIDTH = 10;
|
||||
private static final int BUTTON_HEIGHT = 10;
|
||||
|
||||
private final RecentsHitboxExtender mHitboxExtender = new RecentsHitboxExtender();
|
||||
@Mock
|
||||
View mMockRecentsButton;
|
||||
@Mock
|
||||
View mMockRecentsParent;
|
||||
@Mock
|
||||
DeviceProfile mMockDeviceProfile;
|
||||
@Mock
|
||||
Handler mMockHandler;
|
||||
Context mContext;
|
||||
|
||||
float[] mRecentsCoords = new float[]{0,0};
|
||||
private final Supplier<float[]> mSupplier = () -> mRecentsCoords;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
mContext = instrumentation.getContext();
|
||||
mHitboxExtender.init(mMockRecentsButton, mMockRecentsParent, mMockDeviceProfile, mSupplier,
|
||||
mMockHandler);
|
||||
when(mMockDeviceProfile.getTaskbarOffsetY()).thenReturn(TASKBAR_OFFSET_Y);
|
||||
when(mMockRecentsButton.getContext()).thenReturn(mContext);
|
||||
when(mMockRecentsButton.getWidth()).thenReturn(BUTTON_WIDTH);
|
||||
when(mMockRecentsButton.getHeight()).thenReturn(BUTTON_HEIGHT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noRecentsButtonClick_notActive() {
|
||||
mHitboxExtender.onAnimationProgressToOverview(0);
|
||||
mHitboxExtender.onAnimationProgressToOverview(0.5f);
|
||||
assertFalse(mHitboxExtender.extendedHitboxEnabled());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void recentsButtonClick_active() {
|
||||
mHitboxExtender.onRecentsButtonClicked();
|
||||
mHitboxExtender.onAnimationProgressToOverview(0);
|
||||
mHitboxExtender.onAnimationProgressToOverview(0.5f);
|
||||
assertTrue(mHitboxExtender.extendedHitboxEnabled());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void homeToTaskbar_notActive() {
|
||||
mHitboxExtender.onAnimationProgressToOverview(1);
|
||||
mHitboxExtender.onAnimationProgressToOverview(0.5f);
|
||||
assertFalse(mHitboxExtender.extendedHitboxEnabled());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void animationEndReset() {
|
||||
mHitboxExtender.onRecentsButtonClicked();
|
||||
mHitboxExtender.onAnimationProgressToOverview(0);
|
||||
mHitboxExtender.onAnimationProgressToOverview(0.5f);
|
||||
assertTrue(mHitboxExtender.extendedHitboxEnabled());
|
||||
mHitboxExtender.onAnimationProgressToOverview(1);
|
||||
verify(mMockHandler, times(1)).postDelayed(any(), anyLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void motionWithinHitbox() {
|
||||
mHitboxExtender.onRecentsButtonClicked();
|
||||
mHitboxExtender.onAnimationProgressToOverview(0);
|
||||
mHitboxExtender.onAnimationProgressToOverview(0.5f);
|
||||
assertTrue(mHitboxExtender.extendedHitboxEnabled());
|
||||
// Center width, past height but w/in offset bounds
|
||||
MotionEvent motionEvent = getMotionEvent(ACTION_DOWN,
|
||||
BUTTON_WIDTH / 2, BUTTON_HEIGHT + TASKBAR_OFFSET_Y / 2);
|
||||
assertTrue(mHitboxExtender.onControllerInterceptTouchEvent(motionEvent));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void motionOutsideHitbox() {
|
||||
mHitboxExtender.onRecentsButtonClicked();
|
||||
mHitboxExtender.onAnimationProgressToOverview(0);
|
||||
mHitboxExtender.onAnimationProgressToOverview(0.5f);
|
||||
assertTrue(mHitboxExtender.extendedHitboxEnabled());
|
||||
// Center width, past height and offset
|
||||
MotionEvent motionEvent = getMotionEvent(ACTION_DOWN,
|
||||
BUTTON_WIDTH / 2, BUTTON_HEIGHT + TASKBAR_OFFSET_Y * 2);
|
||||
assertFalse(mHitboxExtender.onControllerInterceptTouchEvent(motionEvent));
|
||||
}
|
||||
|
||||
private MotionEvent getMotionEvent(int action, int x, int y) {
|
||||
return MotionEvent.obtain(0, 0, action, x, y, 0);
|
||||
}
|
||||
}
|
||||
+270
@@ -0,0 +1,270 @@
|
||||
package com.android.launcher3.taskbar;
|
||||
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_BACK_BUTTON_LONGPRESS;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_BACK_BUTTON_TAP;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_HOME_BUTTON_LONGPRESS;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_HOME_BUTTON_TAP;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_OVERVIEW_BUTTON_LONGPRESS;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_OVERVIEW_BUTTON_TAP;
|
||||
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y;
|
||||
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK;
|
||||
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_HOME;
|
||||
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_IME_SWITCH;
|
||||
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_RECENTS;
|
||||
import static com.android.launcher3.taskbar.TaskbarNavButtonController.SCREEN_PIN_LONG_PRESS_THRESHOLD;
|
||||
import static com.android.quickstep.OverviewCommandHelper.TYPE_HOME;
|
||||
import static com.android.quickstep.OverviewCommandHelper.TYPE_TOGGLE;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.launcher3.logging.StatsLogManager;
|
||||
import com.android.quickstep.OverviewCommandHelper;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
import com.android.quickstep.TouchInteractionService;
|
||||
import com.android.quickstep.util.AssistUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class TaskbarNavButtonControllerTest {
|
||||
|
||||
private final static int DISPLAY_ID = 2;
|
||||
|
||||
@Mock
|
||||
SystemUiProxy mockSystemUiProxy;
|
||||
@Mock
|
||||
TouchInteractionService mockService;
|
||||
@Mock
|
||||
OverviewCommandHelper mockCommandHelper;
|
||||
@Mock
|
||||
Handler mockHandler;
|
||||
@Mock
|
||||
AssistUtils mockAssistUtils;
|
||||
@Mock
|
||||
StatsLogManager mockStatsLogManager;
|
||||
@Mock
|
||||
StatsLogManager.StatsLogger mockStatsLogger;
|
||||
@Mock
|
||||
TaskbarControllers mockTaskbarControllers;
|
||||
@Mock
|
||||
TaskbarActivityContext mockTaskbarActivityContext;
|
||||
@Mock
|
||||
View mockView;
|
||||
|
||||
private TaskbarNavButtonController mNavButtonController;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mockService.getDisplayId()).thenReturn(DISPLAY_ID);
|
||||
when(mockService.getOverviewCommandHelper()).thenReturn(mockCommandHelper);
|
||||
when(mockService.getApplicationContext())
|
||||
.thenReturn(InstrumentationRegistry.getInstrumentation().getTargetContext()
|
||||
.getApplicationContext());
|
||||
when(mockStatsLogManager.logger()).thenReturn(mockStatsLogger);
|
||||
when(mockTaskbarControllers.getTaskbarActivityContext())
|
||||
.thenReturn(mockTaskbarActivityContext);
|
||||
doReturn(mockStatsLogManager).when(mockTaskbarActivityContext).getStatsLogManager();
|
||||
mNavButtonController = new TaskbarNavButtonController(mockService,
|
||||
mockSystemUiProxy, mockHandler, mockAssistUtils);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPressBack() {
|
||||
mNavButtonController.onButtonClick(BUTTON_BACK, mockView);
|
||||
verify(mockSystemUiProxy, times(1)).onBackPressed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPressImeSwitcher() {
|
||||
mNavButtonController.onButtonClick(BUTTON_IME_SWITCH, mockView);
|
||||
verify(mockSystemUiProxy, times(1)).onImeSwitcherPressed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPressA11yShortClick() {
|
||||
mNavButtonController.onButtonClick(BUTTON_A11Y, mockView);
|
||||
verify(mockSystemUiProxy, times(1))
|
||||
.notifyAccessibilityButtonClicked(DISPLAY_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPressA11yLongClick() {
|
||||
mNavButtonController.onButtonLongClick(BUTTON_A11Y, mockView);
|
||||
verify(mockSystemUiProxy, times(1)).notifyAccessibilityButtonLongClicked();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongPressHome_enabled_withoutOverride() {
|
||||
mNavButtonController.setAssistantLongPressEnabled(true /*assistantLongPressEnabled*/);
|
||||
when(mockAssistUtils.tryStartAssistOverride(anyInt())).thenReturn(false);
|
||||
|
||||
mNavButtonController.onButtonLongClick(BUTTON_HOME, mockView);
|
||||
verify(mockAssistUtils, times(1)).tryStartAssistOverride(anyInt());
|
||||
verify(mockSystemUiProxy, times(1)).startAssistant(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongPressHome_enabled_withOverride() {
|
||||
mNavButtonController.setAssistantLongPressEnabled(true /*assistantLongPressEnabled*/);
|
||||
when(mockAssistUtils.tryStartAssistOverride(anyInt())).thenReturn(true);
|
||||
|
||||
mNavButtonController.onButtonLongClick(BUTTON_HOME, mockView);
|
||||
verify(mockAssistUtils, times(1)).tryStartAssistOverride(anyInt());
|
||||
verify(mockSystemUiProxy, never()).startAssistant(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongPressHome_disabled_withoutOverride() {
|
||||
mNavButtonController.setAssistantLongPressEnabled(false /*assistantLongPressEnabled*/);
|
||||
when(mockAssistUtils.tryStartAssistOverride(anyInt())).thenReturn(false);
|
||||
|
||||
mNavButtonController.onButtonLongClick(BUTTON_HOME, mockView);
|
||||
verify(mockAssistUtils, never()).tryStartAssistOverride(anyInt());
|
||||
verify(mockSystemUiProxy, never()).startAssistant(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongPressHome_disabled_withOverride() {
|
||||
mNavButtonController.setAssistantLongPressEnabled(false /*assistantLongPressEnabled*/);
|
||||
when(mockAssistUtils.tryStartAssistOverride(anyInt())).thenReturn(true);
|
||||
|
||||
mNavButtonController.onButtonLongClick(BUTTON_HOME, mockView);
|
||||
verify(mockAssistUtils, never()).tryStartAssistOverride(anyInt());
|
||||
verify(mockSystemUiProxy, never()).startAssistant(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPressHome() {
|
||||
mNavButtonController.onButtonClick(BUTTON_HOME, mockView);
|
||||
verify(mockCommandHelper, times(1)).addCommand(TYPE_HOME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPressRecents() {
|
||||
mNavButtonController.onButtonClick(BUTTON_RECENTS, mockView);
|
||||
verify(mockCommandHelper, times(1)).addCommand(TYPE_TOGGLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPressRecentsWithScreenPinned() {
|
||||
mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
|
||||
mNavButtonController.onButtonClick(BUTTON_RECENTS, mockView);
|
||||
verify(mockCommandHelper, times(0)).addCommand(TYPE_TOGGLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongPressBackRecentsNotPinned() {
|
||||
mNavButtonController.onButtonLongClick(BUTTON_RECENTS, mockView);
|
||||
mNavButtonController.onButtonLongClick(BUTTON_BACK, mockView);
|
||||
verify(mockSystemUiProxy, times(0)).stopScreenPinning();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongPressBackRecentsPinned() {
|
||||
mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
|
||||
mNavButtonController.onButtonLongClick(BUTTON_RECENTS, mockView);
|
||||
mNavButtonController.onButtonLongClick(BUTTON_BACK, mockView);
|
||||
verify(mockSystemUiProxy, times(1)).stopScreenPinning();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongPressBackRecentsTooLongPinned() {
|
||||
mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
|
||||
mNavButtonController.onButtonLongClick(BUTTON_RECENTS, mockView);
|
||||
try {
|
||||
Thread.sleep(SCREEN_PIN_LONG_PRESS_THRESHOLD + 5);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
mNavButtonController.onButtonLongClick(BUTTON_BACK, mockView);
|
||||
verify(mockSystemUiProxy, times(0)).stopScreenPinning();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongPressBackRecentsMultipleAttemptPinned() {
|
||||
mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
|
||||
mNavButtonController.onButtonLongClick(BUTTON_RECENTS, mockView);
|
||||
try {
|
||||
Thread.sleep(SCREEN_PIN_LONG_PRESS_THRESHOLD + 5);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
mNavButtonController.onButtonLongClick(BUTTON_BACK, mockView);
|
||||
verify(mockSystemUiProxy, times(0)).stopScreenPinning();
|
||||
|
||||
// Try again w/in threshold
|
||||
mNavButtonController.onButtonLongClick(BUTTON_RECENTS, mockView);
|
||||
mNavButtonController.onButtonLongClick(BUTTON_BACK, mockView);
|
||||
verify(mockSystemUiProxy, times(1)).stopScreenPinning();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongPressHomeScreenPinned() {
|
||||
mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
|
||||
mNavButtonController.onButtonLongClick(BUTTON_HOME, mockView);
|
||||
verify(mockSystemUiProxy, times(0)).startAssistant(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoCallsToNullLogger() {
|
||||
mNavButtonController.onButtonClick(BUTTON_HOME, mockView);
|
||||
verify(mockStatsLogManager, times(0)).logger();
|
||||
verify(mockStatsLogger, times(0)).log(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoCallsAfterNullingOut() {
|
||||
mNavButtonController.init(mockTaskbarControllers);
|
||||
mNavButtonController.onButtonClick(BUTTON_HOME, mockView);
|
||||
mNavButtonController.onDestroy();
|
||||
mNavButtonController.onButtonClick(BUTTON_HOME, mockView);
|
||||
verify(mockStatsLogger, times(1)).log(LAUNCHER_TASKBAR_HOME_BUTTON_TAP);
|
||||
verify(mockStatsLogger, times(0)).log(LAUNCHER_TASKBAR_HOME_BUTTON_LONGPRESS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogOnTap() {
|
||||
mNavButtonController.init(mockTaskbarControllers);
|
||||
mNavButtonController.onButtonClick(BUTTON_HOME, mockView);
|
||||
verify(mockStatsLogger, times(1)).log(LAUNCHER_TASKBAR_HOME_BUTTON_TAP);
|
||||
verify(mockStatsLogger, times(0)).log(LAUNCHER_TASKBAR_HOME_BUTTON_LONGPRESS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogOnLongpress() {
|
||||
mNavButtonController.init(mockTaskbarControllers);
|
||||
mNavButtonController.onButtonLongClick(BUTTON_HOME, mockView);
|
||||
verify(mockStatsLogger, times(1)).log(LAUNCHER_TASKBAR_HOME_BUTTON_LONGPRESS);
|
||||
verify(mockStatsLogger, times(0)).log(LAUNCHER_TASKBAR_HOME_BUTTON_TAP);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBackOverviewLogOnLongpress() {
|
||||
mNavButtonController.init(mockTaskbarControllers);
|
||||
mNavButtonController.onButtonLongClick(BUTTON_RECENTS, mockView);
|
||||
verify(mockStatsLogger, times(1)).log(LAUNCHER_TASKBAR_OVERVIEW_BUTTON_LONGPRESS);
|
||||
verify(mockStatsLogger, times(0)).log(LAUNCHER_TASKBAR_OVERVIEW_BUTTON_TAP);
|
||||
|
||||
mNavButtonController.onButtonLongClick(BUTTON_BACK, mockView);
|
||||
verify(mockStatsLogger, times(1)).log(LAUNCHER_TASKBAR_BACK_BUTTON_LONGPRESS);
|
||||
verify(mockStatsLogger, times(0)).log(LAUNCHER_TASKBAR_BACK_BUTTON_TAP);
|
||||
}
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2021 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;
|
||||
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.AnimatedVectorDrawable;
|
||||
import android.view.View;
|
||||
import android.view.WindowInsetsController;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.systemui.shared.rotation.RotationButton;
|
||||
import com.android.systemui.shared.rotation.RotationButtonController;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
/** SysUI equivalent */
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class NavigationBarRotationContextTest {
|
||||
private static final int DEFAULT_ROTATE = 0;
|
||||
private static final int DEFAULT_DISPLAY = 0;
|
||||
|
||||
|
||||
private RotationButtonController mRotationButtonController;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
Context mTargetContext = InstrumentationRegistry.getTargetContext();
|
||||
final View view = new View(mTargetContext);
|
||||
RotationButton rotationButton = mock(RotationButton.class);
|
||||
mRotationButtonController = new RotationButtonController(mTargetContext, 0, 0, 0, 0, 0, 0,
|
||||
() -> 0);
|
||||
mRotationButtonController.setRotationButton(rotationButton, null);
|
||||
// Due to a mockito issue, only spy the object after setting the initial state
|
||||
mRotationButtonController = spy(mRotationButtonController);
|
||||
final AnimatedVectorDrawable kbd = mock(AnimatedVectorDrawable.class);
|
||||
doReturn(view).when(rotationButton).getCurrentView();
|
||||
doReturn(true).when(rotationButton).acceptRotationProposal();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnInvalidRotationProposal() {
|
||||
mRotationButtonController.onRotationProposal(DEFAULT_ROTATE + 1,
|
||||
false /* isValid */);
|
||||
verify(mRotationButtonController, times(1))
|
||||
.setRotateSuggestionButtonState(false /* visible */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnSameRotationProposal() {
|
||||
mRotationButtonController.onRotationProposal(DEFAULT_ROTATE,
|
||||
true /* isValid */);
|
||||
verify(mRotationButtonController, times(1))
|
||||
.setRotateSuggestionButtonState(false /* visible */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnRotationProposalShowButtonShowNav() {
|
||||
// No navigation bar should not call to set visibility state
|
||||
mRotationButtonController.onBehaviorChanged(DEFAULT_DISPLAY,
|
||||
WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
|
||||
mRotationButtonController.onNavigationBarWindowVisibilityChange(false /* showing */);
|
||||
verify(mRotationButtonController, times(0)).setRotateSuggestionButtonState(
|
||||
false /* visible */);
|
||||
verify(mRotationButtonController, times(0)).setRotateSuggestionButtonState(
|
||||
true /* visible */);
|
||||
|
||||
// No navigation bar with rotation change should not call to set visibility state
|
||||
mRotationButtonController.onRotationProposal(DEFAULT_ROTATE + 1,
|
||||
true /* isValid */);
|
||||
verify(mRotationButtonController, times(0)).setRotateSuggestionButtonState(
|
||||
false /* visible */);
|
||||
verify(mRotationButtonController, times(0)).setRotateSuggestionButtonState(
|
||||
true /* visible */);
|
||||
|
||||
// Since rotation has changed rotation should be pending, show mButton when showing nav bar
|
||||
mRotationButtonController.onNavigationBarWindowVisibilityChange(true /* showing */);
|
||||
verify(mRotationButtonController, times(1)).setRotateSuggestionButtonState(
|
||||
true /* visible */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnRotationProposalShowButton() {
|
||||
// Navigation bar being visible should not call to set visibility state
|
||||
mRotationButtonController.onNavigationBarWindowVisibilityChange(true /* showing */);
|
||||
verify(mRotationButtonController, times(0))
|
||||
.setRotateSuggestionButtonState(false /* visible */);
|
||||
verify(mRotationButtonController, times(0))
|
||||
.setRotateSuggestionButtonState(true /* visible */);
|
||||
|
||||
// Navigation bar is visible and rotation requested
|
||||
mRotationButtonController.onRotationProposal(DEFAULT_ROTATE + 1,
|
||||
true /* isValid */);
|
||||
verify(mRotationButtonController, times(1))
|
||||
.setRotateSuggestionButtonState(true /* visible */);
|
||||
}
|
||||
}
|
||||
+668
@@ -0,0 +1,668 @@
|
||||
/*
|
||||
* 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.app.PendingIntent
|
||||
import android.content.ComponentName
|
||||
import android.content.Intent
|
||||
import android.graphics.Rect
|
||||
import android.os.Handler
|
||||
import android.os.UserHandle
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.android.launcher3.LauncherState
|
||||
import com.android.launcher3.logging.StatsLogManager
|
||||
import com.android.launcher3.logging.StatsLogManager.StatsLogger
|
||||
import com.android.launcher3.model.data.ItemInfo
|
||||
import com.android.launcher3.statehandlers.DepthController
|
||||
import com.android.launcher3.statemanager.StateManager
|
||||
import com.android.launcher3.statemanager.StatefulActivity
|
||||
import com.android.launcher3.util.ComponentKey
|
||||
import com.android.launcher3.util.SplitConfigurationOptions
|
||||
import com.android.quickstep.RecentsModel
|
||||
import com.android.quickstep.SystemUiProxy
|
||||
import com.android.systemui.shared.recents.model.Task
|
||||
import com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50
|
||||
import java.util.function.Consumer
|
||||
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.Mockito.any
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.kotlin.argumentCaptor
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.whenever
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class SplitSelectStateControllerTest {
|
||||
|
||||
private val systemUiProxy: SystemUiProxy = mock()
|
||||
private val depthController: DepthController = mock()
|
||||
private val statsLogManager: StatsLogManager = mock()
|
||||
private val statsLogger: StatsLogger = mock()
|
||||
private val stateManager: StateManager<LauncherState> = mock()
|
||||
private val handler: Handler = mock()
|
||||
private val context: StatefulActivity<*> = mock()
|
||||
private val recentsModel: RecentsModel = mock()
|
||||
private val pendingIntent: PendingIntent = mock()
|
||||
|
||||
private lateinit var splitSelectStateController: SplitSelectStateController
|
||||
|
||||
private val primaryUserHandle = UserHandle(ActivityManager.RunningTaskInfo().userId)
|
||||
private val nonPrimaryUserHandle = UserHandle(ActivityManager.RunningTaskInfo().userId + 10)
|
||||
|
||||
private var taskIdCounter = 0
|
||||
private fun getUniqueId(): Int {
|
||||
return ++taskIdCounter
|
||||
}
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
`when`(statsLogManager.logger()).thenReturn(statsLogger)
|
||||
`when`(statsLogger.withInstanceId(any())).thenReturn(statsLogger)
|
||||
`when`(statsLogger.withItemInfo(any())).thenReturn(statsLogger)
|
||||
splitSelectStateController =
|
||||
SplitSelectStateController(
|
||||
context,
|
||||
handler,
|
||||
stateManager,
|
||||
depthController,
|
||||
statsLogManager,
|
||||
systemUiProxy,
|
||||
recentsModel,
|
||||
null /*activityBackCallback*/
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activeTasks_noMatchingTasks() {
|
||||
val nonMatchingComponent = ComponentKey(ComponentName("no", "match"), primaryUserHandle)
|
||||
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
|
||||
// #findLastActiveTasksAndRunCallback
|
||||
val taskConsumer =
|
||||
Consumer<Array<Task>> { assertNull("No tasks should have matched", it[0] /*task*/) }
|
||||
|
||||
// Capture callback from recentsModel#getTasks()
|
||||
val consumer =
|
||||
argumentCaptor<Consumer<ArrayList<GroupTask>>> {
|
||||
splitSelectStateController.findLastActiveTasksAndRunCallback(
|
||||
listOf(nonMatchingComponent),
|
||||
false /* findExactPairMatch */,
|
||||
taskConsumer
|
||||
)
|
||||
verify(recentsModel).getTasks(capture())
|
||||
}
|
||||
.lastValue
|
||||
|
||||
// Send our mocked tasks
|
||||
consumer.accept(tasks)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activeTasks_singleMatchingTask() {
|
||||
val matchingPackage = "hotdog"
|
||||
val matchingClass = "juice"
|
||||
val matchingComponent =
|
||||
ComponentKey(ComponentName(matchingPackage, matchingClass), primaryUserHandle)
|
||||
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
|
||||
// #findLastActiveTasksAndRunCallback
|
||||
val taskConsumer =
|
||||
Consumer<Array<Task>> {
|
||||
assertEquals(
|
||||
"ComponentName package mismatched",
|
||||
it[0].key.baseIntent.component?.packageName,
|
||||
matchingPackage
|
||||
)
|
||||
assertEquals(
|
||||
"ComponentName class mismatched",
|
||||
it[0].key.baseIntent.component?.className,
|
||||
matchingClass
|
||||
)
|
||||
assertEquals(it[0], groupTask1.task1)
|
||||
}
|
||||
|
||||
// Capture callback from recentsModel#getTasks()
|
||||
val consumer =
|
||||
argumentCaptor<Consumer<ArrayList<GroupTask>>> {
|
||||
splitSelectStateController.findLastActiveTasksAndRunCallback(
|
||||
listOf(matchingComponent),
|
||||
false /* findExactPairMatch */,
|
||||
taskConsumer
|
||||
)
|
||||
verify(recentsModel).getTasks(capture())
|
||||
}
|
||||
.lastValue
|
||||
|
||||
// Send our mocked tasks
|
||||
consumer.accept(tasks)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activeTasks_skipTaskWithDifferentUser() {
|
||||
val matchingPackage = "hotdog"
|
||||
val matchingClass = "juice"
|
||||
val nonPrimaryUserComponent =
|
||||
ComponentKey(ComponentName(matchingPackage, matchingClass), nonPrimaryUserHandle)
|
||||
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
|
||||
// #findLastActiveTasksAndRunCallback
|
||||
val taskConsumer =
|
||||
Consumer<Array<Task>> { assertNull("No tasks should have matched", it[0] /*task*/) }
|
||||
|
||||
// Capture callback from recentsModel#getTasks()
|
||||
val consumer =
|
||||
argumentCaptor<Consumer<ArrayList<GroupTask>>> {
|
||||
splitSelectStateController.findLastActiveTasksAndRunCallback(
|
||||
listOf(nonPrimaryUserComponent),
|
||||
false /* findExactPairMatch */,
|
||||
taskConsumer
|
||||
)
|
||||
verify(recentsModel).getTasks(capture())
|
||||
}
|
||||
.lastValue
|
||||
|
||||
// Send our mocked tasks
|
||||
consumer.accept(tasks)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activeTasks_findTaskAsNonPrimaryUser() {
|
||||
val matchingPackage = "hotdog"
|
||||
val matchingClass = "juice"
|
||||
val nonPrimaryUserComponent =
|
||||
ComponentKey(ComponentName(matchingPackage, matchingClass), nonPrimaryUserHandle)
|
||||
val groupTask1 =
|
||||
generateGroupTask(
|
||||
ComponentName(matchingPackage, matchingClass),
|
||||
nonPrimaryUserHandle,
|
||||
ComponentName("pomegranate", "juice"),
|
||||
nonPrimaryUserHandle
|
||||
)
|
||||
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
|
||||
// #findLastActiveTasksAndRunCallback
|
||||
val taskConsumer =
|
||||
Consumer<Array<Task>> {
|
||||
assertEquals(
|
||||
"ComponentName package mismatched",
|
||||
it[0].key.baseIntent.component?.packageName,
|
||||
matchingPackage
|
||||
)
|
||||
assertEquals(
|
||||
"ComponentName class mismatched",
|
||||
it[0].key.baseIntent.component?.className,
|
||||
matchingClass
|
||||
)
|
||||
assertEquals("userId mismatched", it[0].key.userId, nonPrimaryUserHandle.identifier)
|
||||
assertEquals(it[0], groupTask1.task1)
|
||||
}
|
||||
|
||||
// Capture callback from recentsModel#getTasks()
|
||||
val consumer =
|
||||
argumentCaptor<Consumer<ArrayList<GroupTask>>> {
|
||||
splitSelectStateController.findLastActiveTasksAndRunCallback(
|
||||
listOf(nonPrimaryUserComponent),
|
||||
false /* findExactPairMatch */,
|
||||
taskConsumer
|
||||
)
|
||||
verify(recentsModel).getTasks(capture())
|
||||
}
|
||||
.lastValue
|
||||
|
||||
// Send our mocked tasks
|
||||
consumer.accept(tasks)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activeTasks_multipleMatchMostRecentTask() {
|
||||
val matchingPackage = "hotdog"
|
||||
val matchingClass = "juice"
|
||||
val matchingComponent =
|
||||
ComponentKey(ComponentName(matchingPackage, matchingClass), primaryUserHandle)
|
||||
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
|
||||
// #findLastActiveTasksAndRunCallback
|
||||
val taskConsumer =
|
||||
Consumer<Array<Task>> {
|
||||
assertEquals(
|
||||
"ComponentName package mismatched",
|
||||
it[0].key.baseIntent.component?.packageName,
|
||||
matchingPackage
|
||||
)
|
||||
assertEquals(
|
||||
"ComponentName class mismatched",
|
||||
it[0].key.baseIntent.component?.className,
|
||||
matchingClass
|
||||
)
|
||||
assertEquals(it[0], groupTask1.task1)
|
||||
}
|
||||
|
||||
// Capture callback from recentsModel#getTasks()
|
||||
val consumer =
|
||||
argumentCaptor<Consumer<ArrayList<GroupTask>>> {
|
||||
splitSelectStateController.findLastActiveTasksAndRunCallback(
|
||||
listOf(matchingComponent),
|
||||
false /* findExactPairMatch */,
|
||||
taskConsumer
|
||||
)
|
||||
verify(recentsModel).getTasks(capture())
|
||||
}
|
||||
.lastValue
|
||||
|
||||
// Send our mocked tasks
|
||||
consumer.accept(tasks)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activeTasks_multipleSearchShouldFindTask() {
|
||||
val nonMatchingComponent = ComponentKey(ComponentName("no", "match"), primaryUserHandle)
|
||||
val matchingPackage = "hotdog"
|
||||
val matchingClass = "juice"
|
||||
val matchingComponent =
|
||||
ComponentKey(ComponentName(matchingPackage, matchingClass), primaryUserHandle)
|
||||
|
||||
val groupTask1 =
|
||||
generateGroupTask(ComponentName("hotdog", "pie"), 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
|
||||
// #findLastActiveTasksAndRunCallback
|
||||
val taskConsumer =
|
||||
Consumer<Array<Task>> {
|
||||
assertEquals("Expected array length 2", 2, it.size)
|
||||
assertNull("No tasks should have matched", it[0] /*task*/)
|
||||
assertEquals(
|
||||
"ComponentName package mismatched",
|
||||
it[1].key.baseIntent.component?.packageName,
|
||||
matchingPackage
|
||||
)
|
||||
assertEquals(
|
||||
"ComponentName class mismatched",
|
||||
it[1].key.baseIntent.component?.className,
|
||||
matchingClass
|
||||
)
|
||||
assertEquals(it[1], groupTask2.task2)
|
||||
}
|
||||
|
||||
// Capture callback from recentsModel#getTasks()
|
||||
val consumer =
|
||||
argumentCaptor<Consumer<ArrayList<GroupTask>>> {
|
||||
splitSelectStateController.findLastActiveTasksAndRunCallback(
|
||||
listOf(nonMatchingComponent, matchingComponent),
|
||||
false /* findExactPairMatch */,
|
||||
taskConsumer
|
||||
)
|
||||
verify(recentsModel).getTasks(capture())
|
||||
}
|
||||
.lastValue
|
||||
|
||||
// Send our mocked tasks
|
||||
consumer.accept(tasks)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activeTasks_multipleSearchShouldNotFindSameTaskTwice() {
|
||||
val matchingPackage = "hotdog"
|
||||
val matchingClass = "juice"
|
||||
val matchingComponent =
|
||||
ComponentKey(ComponentName(matchingPackage, matchingClass), primaryUserHandle)
|
||||
|
||||
val groupTask1 =
|
||||
generateGroupTask(ComponentName("hotdog", "pie"), 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
|
||||
// #findLastActiveTasksAndRunCallback
|
||||
val taskConsumer =
|
||||
Consumer<Array<Task>> {
|
||||
assertEquals("Expected array length 2", 2, it.size)
|
||||
assertEquals(
|
||||
"ComponentName package mismatched",
|
||||
it[0].key.baseIntent.component?.packageName,
|
||||
matchingPackage
|
||||
)
|
||||
assertEquals(
|
||||
"ComponentName class mismatched",
|
||||
it[0].key.baseIntent.component?.className,
|
||||
matchingClass
|
||||
)
|
||||
assertEquals(it[0], groupTask2.task2)
|
||||
assertNull("No tasks should have matched", it[1] /*task*/)
|
||||
}
|
||||
|
||||
// Capture callback from recentsModel#getTasks()
|
||||
val consumer =
|
||||
argumentCaptor<Consumer<ArrayList<GroupTask>>> {
|
||||
splitSelectStateController.findLastActiveTasksAndRunCallback(
|
||||
listOf(matchingComponent, matchingComponent),
|
||||
false /* findExactPairMatch */,
|
||||
taskConsumer
|
||||
)
|
||||
verify(recentsModel).getTasks(capture())
|
||||
}
|
||||
.lastValue
|
||||
|
||||
// Send our mocked tasks
|
||||
consumer.accept(tasks)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activeTasks_multipleSearchShouldFindDifferentInstancesOfSameTask() {
|
||||
val matchingPackage = "hotdog"
|
||||
val matchingClass = "juice"
|
||||
val matchingComponent =
|
||||
ComponentKey(ComponentName(matchingPackage, matchingClass), primaryUserHandle)
|
||||
|
||||
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
|
||||
// #findLastActiveTasksAndRunCallback
|
||||
val taskConsumer =
|
||||
Consumer<Array<Task>> {
|
||||
assertEquals("Expected array length 2", 2, it.size)
|
||||
assertEquals(
|
||||
"ComponentName package mismatched",
|
||||
it[0].key.baseIntent.component?.packageName,
|
||||
matchingPackage
|
||||
)
|
||||
assertEquals(
|
||||
"ComponentName class mismatched",
|
||||
it[0].key.baseIntent.component?.className,
|
||||
matchingClass
|
||||
)
|
||||
assertEquals(it[0], groupTask1.task1)
|
||||
assertEquals(
|
||||
"ComponentName package mismatched",
|
||||
it[1].key.baseIntent.component?.packageName,
|
||||
matchingPackage
|
||||
)
|
||||
assertEquals(
|
||||
"ComponentName class mismatched",
|
||||
it[1].key.baseIntent.component?.className,
|
||||
matchingClass
|
||||
)
|
||||
assertEquals(it[1], groupTask2.task2)
|
||||
}
|
||||
|
||||
// Capture callback from recentsModel#getTasks()
|
||||
val consumer =
|
||||
argumentCaptor<Consumer<ArrayList<GroupTask>>> {
|
||||
splitSelectStateController.findLastActiveTasksAndRunCallback(
|
||||
listOf(matchingComponent, matchingComponent),
|
||||
false /* findExactPairMatch */,
|
||||
taskConsumer
|
||||
)
|
||||
verify(recentsModel).getTasks(capture())
|
||||
}
|
||||
.lastValue
|
||||
|
||||
// Send our mocked tasks
|
||||
consumer.accept(tasks)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activeTasks_multipleSearchShouldFindExactPairMatch() {
|
||||
val matchingPackage = "hotdog"
|
||||
val matchingClass = "juice"
|
||||
val matchingComponent =
|
||||
ComponentKey(ComponentName(matchingPackage, matchingClass), primaryUserHandle)
|
||||
val matchingPackage2 = "pomegranate"
|
||||
val matchingClass2 = "juice"
|
||||
val matchingComponent2 =
|
||||
ComponentKey(ComponentName(matchingPackage2, matchingClass2), primaryUserHandle)
|
||||
|
||||
val groupTask1 =
|
||||
generateGroupTask(ComponentName("hotdog", "pie"), ComponentName("pumpkin", "pie"))
|
||||
val groupTask2 =
|
||||
generateGroupTask(
|
||||
ComponentName(matchingPackage2, matchingClass2),
|
||||
ComponentName(matchingPackage, matchingClass)
|
||||
)
|
||||
val groupTask3 =
|
||||
generateGroupTask(
|
||||
ComponentName("hotdog", "pie"),
|
||||
ComponentName(matchingPackage, matchingClass)
|
||||
)
|
||||
val tasks: ArrayList<GroupTask> = ArrayList()
|
||||
tasks.add(groupTask3)
|
||||
tasks.add(groupTask2)
|
||||
tasks.add(groupTask1)
|
||||
|
||||
// Assertions happen in the callback we get from what we pass into
|
||||
// #findLastActiveTasksAndRunCallback
|
||||
val taskConsumer =
|
||||
Consumer<Array<Task>> {
|
||||
assertEquals("Expected array length 2", 2, it.size)
|
||||
assertEquals("Found wrong task", it[0], groupTask2.task1)
|
||||
}
|
||||
|
||||
// Capture callback from recentsModel#getTasks()
|
||||
val consumer =
|
||||
argumentCaptor<Consumer<ArrayList<GroupTask>>> {
|
||||
splitSelectStateController.findLastActiveTasksAndRunCallback(
|
||||
listOf(matchingComponent2, matchingComponent),
|
||||
true /* findExactPairMatch */,
|
||||
taskConsumer
|
||||
)
|
||||
verify(recentsModel).getTasks(capture())
|
||||
}
|
||||
.lastValue
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun secondPendingIntentSet() {
|
||||
val itemInfo = ItemInfo()
|
||||
val itemInfo2 = ItemInfo()
|
||||
whenever(pendingIntent.creatorUserHandle).thenReturn(primaryUserHandle)
|
||||
splitSelectStateController.setInitialTaskSelect(null, 0, itemInfo, null, 1)
|
||||
splitSelectStateController.setSecondTask(pendingIntent, itemInfo2)
|
||||
assertTrue(splitSelectStateController.isBothSplitAppsConfirmed)
|
||||
}
|
||||
|
||||
// Generate GroupTask with default userId.
|
||||
private fun generateGroupTask(
|
||||
task1ComponentName: ComponentName,
|
||||
task2ComponentName: ComponentName
|
||||
): GroupTask {
|
||||
val task1 = Task()
|
||||
var taskInfo = ActivityManager.RunningTaskInfo()
|
||||
taskInfo.taskId = getUniqueId()
|
||||
var intent = Intent()
|
||||
intent.component = task1ComponentName
|
||||
taskInfo.baseIntent = intent
|
||||
task1.key = Task.TaskKey(taskInfo)
|
||||
|
||||
val task2 = Task()
|
||||
taskInfo = ActivityManager.RunningTaskInfo()
|
||||
taskInfo.taskId = getUniqueId()
|
||||
intent = Intent()
|
||||
intent.component = task2ComponentName
|
||||
taskInfo.baseIntent = intent
|
||||
task2.key = Task.TaskKey(taskInfo)
|
||||
return GroupTask(
|
||||
task1,
|
||||
task2,
|
||||
SplitConfigurationOptions.SplitBounds(Rect(), Rect(), -1, -1, SNAP_TO_50_50)
|
||||
)
|
||||
}
|
||||
|
||||
// Generate GroupTask with custom user handles.
|
||||
private fun generateGroupTask(
|
||||
task1ComponentName: ComponentName,
|
||||
userHandle1: UserHandle,
|
||||
task2ComponentName: ComponentName,
|
||||
userHandle2: UserHandle
|
||||
): GroupTask {
|
||||
val task1 = Task()
|
||||
var taskInfo = ActivityManager.RunningTaskInfo()
|
||||
taskInfo.taskId = getUniqueId()
|
||||
// Apply custom userHandle1
|
||||
taskInfo.userId = userHandle1.identifier
|
||||
var intent = Intent()
|
||||
intent.component = task1ComponentName
|
||||
taskInfo.baseIntent = intent
|
||||
task1.key = Task.TaskKey(taskInfo)
|
||||
val task2 = Task()
|
||||
taskInfo = ActivityManager.RunningTaskInfo()
|
||||
taskInfo.taskId = getUniqueId()
|
||||
// Apply custom userHandle2
|
||||
taskInfo.userId = userHandle2.identifier
|
||||
intent = Intent()
|
||||
intent.component = task2ComponentName
|
||||
taskInfo.baseIntent = intent
|
||||
task2.key = Task.TaskKey(taskInfo)
|
||||
return GroupTask(
|
||||
task1,
|
||||
task2,
|
||||
SplitConfigurationOptions.SplitBounds(Rect(), Rect(), -1, -1, SNAP_TO_50_50)
|
||||
)
|
||||
}
|
||||
}
|
||||
+510
@@ -0,0 +1,510 @@
|
||||
/*
|
||||
* 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 static com.android.quickstep.util.TaskGridNavHelper.CLEAR_ALL_PLACEHOLDER_ID;
|
||||
import static com.android.quickstep.util.TaskGridNavHelper.INVALID_FOCUSED_TASK_ID;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import com.android.launcher3.util.IntArray;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class TaskGridNavHelperTest {
|
||||
|
||||
@Test
|
||||
public void equalLengthRows_noFocused_onTop_pressDown_goesToBottom() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int currentPageTaskViewId = 1;
|
||||
int delta = 1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_DOWN;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", 2, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalLengthRows_noFocused_onTop_pressUp_goesToBottom() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int currentPageTaskViewId = 1;
|
||||
int delta = 1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_UP;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", 2, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalLengthRows_noFocused_onBottom_pressDown_goesToTop() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int currentPageTaskViewId = 2;
|
||||
int delta = 1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_DOWN;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", 1, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalLengthRows_noFocused_onBottom_pressUp_goesToTop() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int currentPageTaskViewId = 2;
|
||||
int delta = 1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_UP;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", 1, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalLengthRows_noFocused_onTop_pressLeft_goesLeft() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int currentPageTaskViewId = 1;
|
||||
int delta = 1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", 3, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalLengthRows_noFocused_onBottom_pressLeft_goesLeft() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int currentPageTaskViewId = 2;
|
||||
int delta = 1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", 4, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalLengthRows_noFocused_onTop_secondItem_pressRight_goesRight() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int currentPageTaskViewId = 3;
|
||||
int delta = -1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", 1, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalLengthRows_noFocused_onBottom_secondItem_pressRight_goesRight() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int currentPageTaskViewId = 4;
|
||||
int delta = -1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", 2, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalLengthRows_noFocused_onTop_pressRight_cycleToClearAll() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int currentPageTaskViewId = 1;
|
||||
int delta = -1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", CLEAR_ALL_PLACEHOLDER_ID, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalLengthRows_noFocused_onBottom_pressRight_cycleToClearAll() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int currentPageTaskViewId = 2;
|
||||
int delta = -1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", CLEAR_ALL_PLACEHOLDER_ID, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalLengthRows_noFocused_onTop_lastItem_pressLeft_toClearAll() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int currentPageTaskViewId = 5;
|
||||
int delta = 1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", CLEAR_ALL_PLACEHOLDER_ID, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalLengthRows_noFocused_onBottom_lastItem_pressLeft_toClearAll() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int currentPageTaskViewId = 6;
|
||||
int delta = 1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", CLEAR_ALL_PLACEHOLDER_ID, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalLengthRows_noFocused_onClearAll_pressLeft_cycleToFirst() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID;
|
||||
int delta = 1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", 1, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalLengthRows_noFocused_onClearAll_pressRight_toLastInBottom() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID;
|
||||
int delta = -1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", 6, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalLengthRows_withFocused_onFocused_pressLeft_toTop() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int focusedTaskId = 99;
|
||||
int currentPageTaskViewId = focusedTaskId;
|
||||
int delta = 1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, focusedTaskId);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", 1, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalLengthRows_withFocused_onFocused_pressUp_stayOnFocused() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int focusedTaskId = 99;
|
||||
int currentPageTaskViewId = focusedTaskId;
|
||||
int delta = 1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_UP;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, focusedTaskId);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", focusedTaskId, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalLengthRows_withFocused_onFocused_pressDown_stayOnFocused() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int focusedTaskId = 99;
|
||||
int currentPageTaskViewId = focusedTaskId;
|
||||
int delta = 1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_DOWN;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, focusedTaskId);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", focusedTaskId, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalLengthRows_withFocused_onFocused_pressRight_cycleToClearAll() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int focusedTaskId = 99;
|
||||
int currentPageTaskViewId = focusedTaskId;
|
||||
int delta = -1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, focusedTaskId);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", CLEAR_ALL_PLACEHOLDER_ID, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalLengthRows_withFocused_onClearAll_pressLeft_cycleToFocusedTask() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int focusedTaskId = 99;
|
||||
int currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID;
|
||||
int delta = 1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, focusedTaskId);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", focusedTaskId, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void longerTopRow_noFocused_atEndTopBeyondBottom_pressDown_stayTop() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5, 7);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int currentPageTaskViewId = 7;
|
||||
int delta = 1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_DOWN;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", 7, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void longerTopRow_noFocused_atEndTopBeyondBottom_pressUp_stayTop() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5, 7);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int currentPageTaskViewId = 7;
|
||||
int delta = 1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_UP;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", 7, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void longerTopRow_noFocused_atEndBottom_pressLeft_goToTop() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5, 7);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int currentPageTaskViewId = 6;
|
||||
int delta = 1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", 7, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void longerTopRow_noFocused_atClearAll_pressRight_goToLonger() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5, 7);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID;
|
||||
int delta = -1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", 7, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void longerBottomRow_noFocused_atClearAll_pressRight_goToLonger() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6, 7);
|
||||
int currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID;
|
||||
int delta = -1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", 7, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalLengthRows_noFocused_onTop_pressTab_goesToBottom() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int currentPageTaskViewId = 1;
|
||||
int delta = 1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_TAB;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", 2, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalLengthRows_noFocused_onBottom_pressTab_goesToNextTop() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int currentPageTaskViewId = 2;
|
||||
int delta = 1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_TAB;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", 3, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalLengthRows_noFocused_onTop_pressTabWithShift_goesToPreviousBottom() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int currentPageTaskViewId = 3;
|
||||
int delta = -1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_TAB;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", 2, nextGridPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalLengthRows_noFocused_onBottom_pressTabWithShift_goesToTop() {
|
||||
IntArray topIds = IntArray.wrap(1, 3, 5);
|
||||
IntArray bottomIds = IntArray.wrap(2, 4, 6);
|
||||
int currentPageTaskViewId = 2;
|
||||
int delta = -1;
|
||||
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_TAB;
|
||||
boolean cycle = true;
|
||||
TaskGridNavHelper taskGridNavHelper =
|
||||
new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
|
||||
|
||||
int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
|
||||
assertEquals("Wrong next page returned.", 1, nextGridPage);
|
||||
}
|
||||
}
|
||||
+281
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* 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 static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertNotNull;
|
||||
import static junit.framework.Assert.assertNull;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
@SmallTest
|
||||
public class TaskKeyByLastActiveTimeCacheTest {
|
||||
@Test
|
||||
public void add() {
|
||||
TaskKeyByLastActiveTimeCache<ThumbnailData> cache = new TaskKeyByLastActiveTimeCache<>(3);
|
||||
Task.TaskKey key1 = new Task.TaskKey(1, 0, new Intent(),
|
||||
new ComponentName("", ""), 0, 1);
|
||||
ThumbnailData data1 = new ThumbnailData();
|
||||
cache.put(key1, data1);
|
||||
|
||||
Task.TaskKey key2 = new Task.TaskKey(2, 0, new Intent(),
|
||||
new ComponentName("", ""), 0, 2);
|
||||
ThumbnailData data2 = new ThumbnailData();
|
||||
cache.put(key2, data2);
|
||||
|
||||
assertEquals(2, cache.getSize());
|
||||
assertEquals(data1, cache.getAndInvalidateIfModified(key1));
|
||||
assertEquals(data2, cache.getAndInvalidateIfModified(key2));
|
||||
|
||||
assertEquals(2, cache.getQueue().size());
|
||||
assertEquals(key1, cache.getQueue().poll());
|
||||
assertEquals(key2, cache.getQueue().poll());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addSameTasksWithSameLastActiveTimeTwice() {
|
||||
// Add 2 tasks with same id and last active time, it should only have 1 entry in cache
|
||||
TaskKeyByLastActiveTimeCache<ThumbnailData> cache = new TaskKeyByLastActiveTimeCache<>(3);
|
||||
Task.TaskKey key1 = new Task.TaskKey(1, 0, new Intent(),
|
||||
new ComponentName("", ""), 0, 1000);
|
||||
ThumbnailData data1 = new ThumbnailData();
|
||||
cache.put(key1, data1);
|
||||
|
||||
Task.TaskKey key2 = new Task.TaskKey(1, 0, new Intent(),
|
||||
new ComponentName("", ""), 0, 1000);
|
||||
ThumbnailData data2 = new ThumbnailData();
|
||||
cache.put(key2, data2);
|
||||
|
||||
assertEquals(1, cache.getSize());
|
||||
assertEquals(data2, cache.getAndInvalidateIfModified(key2));
|
||||
|
||||
assertEquals(1, cache.getQueue().size());
|
||||
assertEquals(key2, cache.getQueue().poll());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addSameTasksWithDifferentLastActiveTime() {
|
||||
// Add 2 tasks with same id and different last active time, it should only have the
|
||||
// higher last active time entry
|
||||
TaskKeyByLastActiveTimeCache<ThumbnailData> cache = new TaskKeyByLastActiveTimeCache<>(3);
|
||||
Task.TaskKey key1 = new Task.TaskKey(1, 0, new Intent(),
|
||||
new ComponentName("", ""), 0, 1000);
|
||||
ThumbnailData data1 = new ThumbnailData();
|
||||
cache.put(key1, data1);
|
||||
|
||||
Task.TaskKey key2 = new Task.TaskKey(1, 0, new Intent(),
|
||||
new ComponentName("", ""), 0, 2000);
|
||||
ThumbnailData data2 = new ThumbnailData();
|
||||
cache.put(key2, data2);
|
||||
|
||||
assertEquals(1, cache.getSize());
|
||||
assertEquals(data2, cache.getAndInvalidateIfModified(key2));
|
||||
|
||||
assertEquals(1, cache.getQueue().size());
|
||||
Task.TaskKey queueKey = cache.getQueue().poll();
|
||||
assertEquals(key2, queueKey);
|
||||
// TaskKey's equal method does not check last active time, so we check here
|
||||
assertEquals(2000, queueKey.lastActiveTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void remove() {
|
||||
TaskKeyByLastActiveTimeCache<ThumbnailData> cache = new TaskKeyByLastActiveTimeCache<>(3);
|
||||
Task.TaskKey key1 = new Task.TaskKey(1, 0, new Intent(),
|
||||
new ComponentName("", ""), 0, 0);
|
||||
cache.put(key1, new ThumbnailData());
|
||||
|
||||
cache.remove(key1);
|
||||
|
||||
assertEquals(0, cache.getSize());
|
||||
assertEquals(0, cache.getQueue().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeByStubKey() {
|
||||
TaskKeyByLastActiveTimeCache<ThumbnailData> cache = new TaskKeyByLastActiveTimeCache<>(3);
|
||||
Task.TaskKey key1 = new Task.TaskKey(1, 1, new Intent(),
|
||||
new ComponentName("", ""), 1, 100);
|
||||
cache.put(key1, new ThumbnailData());
|
||||
|
||||
Task.TaskKey stubKey = new Task.TaskKey(1, 0, new Intent(),
|
||||
new ComponentName("", ""), 0, 0);
|
||||
cache.remove(stubKey);
|
||||
|
||||
assertEquals(0, cache.getSize());
|
||||
assertEquals(0, cache.getQueue().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void evictAll() {
|
||||
TaskKeyByLastActiveTimeCache<ThumbnailData> cache = new TaskKeyByLastActiveTimeCache<>(3);
|
||||
Task.TaskKey key1 = new Task.TaskKey(1, 0, new Intent(),
|
||||
new ComponentName("", ""), 0, 0);
|
||||
cache.put(key1, new ThumbnailData());
|
||||
Task.TaskKey key2 = new Task.TaskKey(2, 0, new Intent(),
|
||||
new ComponentName("", ""), 0, 0);
|
||||
cache.put(key2, new ThumbnailData());
|
||||
|
||||
cache.evictAll();
|
||||
|
||||
assertEquals(0, cache.getSize());
|
||||
assertEquals(0, cache.getQueue().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeAllByPredicate() {
|
||||
TaskKeyByLastActiveTimeCache<ThumbnailData> cache = new TaskKeyByLastActiveTimeCache<>(3);
|
||||
// Add user 1's tasks
|
||||
Task.TaskKey user1Key1 = new Task.TaskKey(1, 0, new Intent(),
|
||||
new ComponentName("", ""), 1, 0);
|
||||
cache.put(user1Key1, new ThumbnailData());
|
||||
Task.TaskKey user1Key2 = new Task.TaskKey(2, 0, new Intent(),
|
||||
new ComponentName("", ""), 1, 0);
|
||||
cache.put(user1Key2, new ThumbnailData());
|
||||
// Add user 2's task
|
||||
Task.TaskKey user2Key = new Task.TaskKey(3, 0, new Intent(),
|
||||
new ComponentName("", ""), 2, 0);
|
||||
ThumbnailData user2Data = new ThumbnailData();
|
||||
cache.put(user2Key, user2Data);
|
||||
|
||||
cache.removeAll(key -> key.userId == 1);
|
||||
|
||||
// Only user 2's task remains
|
||||
assertEquals(1, cache.getSize());
|
||||
assertEquals(user2Data, cache.getAndInvalidateIfModified(user2Key));
|
||||
|
||||
assertEquals(1, cache.getQueue().size());
|
||||
assertEquals(user2Key, cache.getQueue().poll());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAndInvalidateIfModified() {
|
||||
TaskKeyByLastActiveTimeCache<ThumbnailData> cache = new TaskKeyByLastActiveTimeCache<>(3);
|
||||
// Add user 1's tasks
|
||||
Task.TaskKey key1 = new Task.TaskKey(1, 0, new Intent(),
|
||||
new ComponentName("", ""), 1, 0);
|
||||
ThumbnailData data1 = new ThumbnailData();
|
||||
cache.put(key1, data1);
|
||||
|
||||
// Get result with task key of same last active time
|
||||
Task.TaskKey keyWithSameActiveTime = new Task.TaskKey(1, 0, new Intent(),
|
||||
new ComponentName("", ""), 1, 0);
|
||||
ThumbnailData result1 = cache.getAndInvalidateIfModified(keyWithSameActiveTime);
|
||||
assertEquals(data1, result1);
|
||||
assertEquals(1, cache.getQueue().size());
|
||||
|
||||
// Invalidate result with task key of new last active time
|
||||
Task.TaskKey keyWithNewActiveTime = new Task.TaskKey(1, 0, new Intent(),
|
||||
new ComponentName("", ""), 1, 1);
|
||||
ThumbnailData result2 = cache.getAndInvalidateIfModified(keyWithNewActiveTime);
|
||||
// No entry is retrieved because the key has higher last active time
|
||||
assertNull(result2);
|
||||
assertEquals(0, cache.getSize());
|
||||
assertEquals(0, cache.getQueue().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeByLastActiveTimeWhenOverMaxSize() {
|
||||
TaskKeyByLastActiveTimeCache<ThumbnailData> cache = new TaskKeyByLastActiveTimeCache<>(2);
|
||||
Task.TaskKey key1 = new Task.TaskKey(1, 0, new Intent(),
|
||||
new ComponentName("", ""), 0, 200);
|
||||
ThumbnailData task1 = new ThumbnailData();
|
||||
cache.put(key1, task1);
|
||||
Task.TaskKey key2 = new Task.TaskKey(2, 0, new Intent(),
|
||||
new ComponentName("", ""), 0, 100);
|
||||
ThumbnailData task2 = new ThumbnailData();
|
||||
cache.put(key2, task2);
|
||||
|
||||
// Add the 3rd entry which will exceed the max cache size
|
||||
Task.TaskKey key3 = new Task.TaskKey(3, 0, new Intent(),
|
||||
new ComponentName("", ""), 0, 300);
|
||||
ThumbnailData task3 = new ThumbnailData();
|
||||
cache.put(key3, task3);
|
||||
|
||||
// Assert map size and check the remaining entries have higher active time
|
||||
assertEquals(2, cache.getSize());
|
||||
assertEquals(task1, cache.getAndInvalidateIfModified(key1));
|
||||
assertEquals(task3, cache.getAndInvalidateIfModified(key3));
|
||||
assertNull(cache.getAndInvalidateIfModified(key2));
|
||||
|
||||
// Assert queue size and check the remaining entries have higher active time
|
||||
assertEquals(2, cache.getQueue().size());
|
||||
Task.TaskKey queueKey1 = cache.getQueue().poll();
|
||||
assertEquals(key1, queueKey1);
|
||||
assertEquals(200, queueKey1.lastActiveTime);
|
||||
Task.TaskKey queueKey2 = cache.getQueue().poll();
|
||||
assertEquals(key3, queueKey2);
|
||||
assertEquals(300, queueKey2.lastActiveTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateIfAlreadyInCache() {
|
||||
TaskKeyByLastActiveTimeCache<ThumbnailData> cache = new TaskKeyByLastActiveTimeCache<>(2);
|
||||
Task.TaskKey key1 = new Task.TaskKey(1, 0, new Intent(),
|
||||
new ComponentName("", ""), 0, 200);
|
||||
cache.put(key1, new ThumbnailData());
|
||||
|
||||
// Update original data to new data
|
||||
ThumbnailData newData = new ThumbnailData();
|
||||
cache.updateIfAlreadyInCache(key1.id, newData);
|
||||
|
||||
// Data is updated to newData successfully
|
||||
ThumbnailData result = cache.getAndInvalidateIfModified(key1);
|
||||
assertEquals(newData, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateCacheSizeAndInvalidateExcess() {
|
||||
// Last active time are not in-sync with insertion order to simulate the real async case
|
||||
TaskKeyByLastActiveTimeCache<ThumbnailData> cache = new TaskKeyByLastActiveTimeCache<>(4);
|
||||
Task.TaskKey key1 = new Task.TaskKey(1, 0, new Intent(),
|
||||
new ComponentName("", ""), 0, 200);
|
||||
cache.put(key1, new ThumbnailData());
|
||||
|
||||
Task.TaskKey key2 = new Task.TaskKey(2, 0, new Intent(),
|
||||
new ComponentName("", ""), 0, 100);
|
||||
cache.put(key2, new ThumbnailData());
|
||||
|
||||
Task.TaskKey key3 = new Task.TaskKey(3, 0, new Intent(),
|
||||
new ComponentName("", ""), 0, 400);
|
||||
cache.put(key3, new ThumbnailData());
|
||||
|
||||
Task.TaskKey key4 = new Task.TaskKey(4, 0, new Intent(),
|
||||
new ComponentName("", ""), 0, 300);
|
||||
cache.put(key4, new ThumbnailData());
|
||||
|
||||
// Check that it has 4 entries before cache size changes
|
||||
assertEquals(4, cache.getSize());
|
||||
assertEquals(4, cache.getQueue().size());
|
||||
|
||||
// Update size to 2
|
||||
cache.updateCacheSizeAndRemoveExcess(2);
|
||||
|
||||
// Number of entries becomes 2, only key3 and key4 remain
|
||||
assertEquals(2, cache.getSize());
|
||||
assertEquals(2, cache.getQueue().size());
|
||||
assertNotNull(cache.getAndInvalidateIfModified(key3));
|
||||
assertNotNull(cache.getAndInvalidateIfModified(key4));
|
||||
}
|
||||
}
|
||||
+276
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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 static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.RemoteAnimationTarget;
|
||||
import android.view.Surface;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.util.DisplayController;
|
||||
import com.android.launcher3.util.DisplayController.Info;
|
||||
import com.android.launcher3.util.LauncherModelHelper;
|
||||
import com.android.launcher3.util.NavigationMode;
|
||||
import com.android.launcher3.util.RotationUtils;
|
||||
import com.android.launcher3.util.WindowBounds;
|
||||
import com.android.launcher3.util.window.CachedDisplayInfo;
|
||||
import com.android.launcher3.util.window.WindowManagerProxy;
|
||||
import com.android.quickstep.FallbackActivityInterface;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
import com.android.quickstep.util.SurfaceTransaction.MockProperties;
|
||||
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.TypeSafeMatcher;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class TaskViewSimulatorTest {
|
||||
|
||||
@Test
|
||||
public void taskProperlyScaled_portrait_noRotation_sameInsets1() {
|
||||
new TaskMatrixVerifier()
|
||||
.withLauncherSize(1200, 2450)
|
||||
.withDensityDpi(420)
|
||||
.withInsets(new Rect(0, 80, 0, 120))
|
||||
.verifyNoTransforms();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void taskProperlyScaled_portrait_noRotation_sameInsets2() {
|
||||
new TaskMatrixVerifier()
|
||||
.withLauncherSize(1200, 2450)
|
||||
.withDensityDpi(420)
|
||||
.withInsets(new Rect(55, 80, 55, 120))
|
||||
.verifyNoTransforms();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void taskProperlyScaled_landscape_noRotation_sameInsets1() {
|
||||
new TaskMatrixVerifier()
|
||||
.withLauncherSize(2450, 1250)
|
||||
.withDensityDpi(420)
|
||||
.withInsets(new Rect(0, 80, 0, 40))
|
||||
.verifyNoTransforms();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void taskProperlyScaled_landscape_noRotation_sameInsets2() {
|
||||
new TaskMatrixVerifier()
|
||||
.withLauncherSize(2450, 1250)
|
||||
.withDensityDpi(420)
|
||||
.withInsets(new Rect(0, 80, 120, 0))
|
||||
.verifyNoTransforms();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void taskProperlyScaled_landscape_noRotation_sameInsets3() {
|
||||
new TaskMatrixVerifier()
|
||||
.withLauncherSize(2450, 1250)
|
||||
.withDensityDpi(420)
|
||||
.withInsets(new Rect(55, 80, 55, 120))
|
||||
.verifyNoTransforms();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void taskProperlyScaled_landscape_rotated() {
|
||||
new TaskMatrixVerifier()
|
||||
.withLauncherSize(1200, 2450)
|
||||
.withDensityDpi(420)
|
||||
.withInsets(new Rect(0, 80, 0, 120))
|
||||
.withAppBounds(
|
||||
new Rect(0, 0, 2450, 1200),
|
||||
new Rect(0, 80, 0, 120),
|
||||
Surface.ROTATION_90)
|
||||
.verifyNoTransforms();
|
||||
}
|
||||
|
||||
private static class TaskMatrixVerifier extends TransformParams {
|
||||
|
||||
private Point mDisplaySize = new Point();
|
||||
private int mDensityDpi = DisplayMetrics.DENSITY_DEFAULT;
|
||||
private Rect mDisplayInsets = new Rect();
|
||||
private Rect mAppBounds = new Rect();
|
||||
private Rect mLauncherInsets = new Rect();
|
||||
|
||||
private Rect mAppInsets;
|
||||
|
||||
private int mAppRotation = -1;
|
||||
private DeviceProfile mDeviceProfile;
|
||||
|
||||
TaskMatrixVerifier withLauncherSize(int width, int height) {
|
||||
mDisplaySize.set(width, height);
|
||||
if (mAppBounds.isEmpty()) {
|
||||
mAppBounds.set(0, 0, width, height);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
TaskMatrixVerifier withDensityDpi(int densityDpi) {
|
||||
mDensityDpi = densityDpi;
|
||||
return this;
|
||||
}
|
||||
|
||||
TaskMatrixVerifier withInsets(Rect insets) {
|
||||
mDisplayInsets.set(insets);
|
||||
mLauncherInsets.set(insets);
|
||||
return this;
|
||||
}
|
||||
|
||||
TaskMatrixVerifier withAppBounds(Rect bounds, Rect insets, int appRotation) {
|
||||
mAppBounds.set(bounds);
|
||||
mAppInsets = insets;
|
||||
mAppRotation = appRotation;
|
||||
return this;
|
||||
}
|
||||
|
||||
void verifyNoTransforms() {
|
||||
LauncherModelHelper helper = new LauncherModelHelper();
|
||||
try {
|
||||
helper.sandboxContext.allow(SystemUiProxy.INSTANCE);
|
||||
int rotation = mDisplaySize.x > mDisplaySize.y
|
||||
? Surface.ROTATION_90 : Surface.ROTATION_0;
|
||||
CachedDisplayInfo cdi = new CachedDisplayInfo(mDisplaySize, rotation);
|
||||
WindowBounds wm = new WindowBounds(
|
||||
new Rect(0, 0, mDisplaySize.x, mDisplaySize.y),
|
||||
mDisplayInsets);
|
||||
List<WindowBounds> allBounds = new ArrayList<>(4);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Rect boundsR = new Rect(wm.bounds);
|
||||
Rect insetsR = new Rect(wm.insets);
|
||||
|
||||
RotationUtils.rotateRect(insetsR, RotationUtils.deltaRotation(rotation, i));
|
||||
RotationUtils.rotateRect(boundsR, RotationUtils.deltaRotation(rotation, i));
|
||||
boundsR.set(0, 0, Math.abs(boundsR.width()), Math.abs(boundsR.height()));
|
||||
allBounds.add(new WindowBounds(boundsR, insetsR));
|
||||
}
|
||||
|
||||
WindowManagerProxy wmProxy = mock(WindowManagerProxy.class);
|
||||
doReturn(cdi).when(wmProxy).getDisplayInfo(any());
|
||||
doReturn(wm).when(wmProxy).getRealBounds(any(), any());
|
||||
doReturn(NavigationMode.NO_BUTTON).when(wmProxy).getNavigationMode(any());
|
||||
|
||||
ArrayMap<CachedDisplayInfo, List<WindowBounds>> perDisplayBoundsCache =
|
||||
new ArrayMap<>();
|
||||
perDisplayBoundsCache.put(cdi.normalize(wmProxy), allBounds);
|
||||
|
||||
Configuration configuration = new Configuration();
|
||||
configuration.densityDpi = mDensityDpi;
|
||||
Context configurationContext = helper.sandboxContext.createConfigurationContext(
|
||||
configuration);
|
||||
|
||||
DisplayController.Info info = new Info(
|
||||
configurationContext, wmProxy, perDisplayBoundsCache);
|
||||
|
||||
DisplayController mockController = mock(DisplayController.class);
|
||||
when(mockController.getInfo()).thenReturn(info);
|
||||
helper.sandboxContext.putObject(DisplayController.INSTANCE, mockController);
|
||||
|
||||
mDeviceProfile = InvariantDeviceProfile.INSTANCE.get(helper.sandboxContext)
|
||||
.getBestMatch(mAppBounds.width(), mAppBounds.height(), rotation);
|
||||
mDeviceProfile.updateInsets(mLauncherInsets);
|
||||
|
||||
TaskViewSimulator tvs = new TaskViewSimulator(helper.sandboxContext,
|
||||
FallbackActivityInterface.INSTANCE);
|
||||
tvs.setDp(mDeviceProfile);
|
||||
|
||||
int launcherRotation = info.rotation;
|
||||
if (mAppRotation < 0) {
|
||||
mAppRotation = launcherRotation;
|
||||
}
|
||||
|
||||
tvs.getOrientationState().update(launcherRotation, mAppRotation);
|
||||
if (mAppInsets == null) {
|
||||
mAppInsets = new Rect(mLauncherInsets);
|
||||
}
|
||||
tvs.setPreviewBounds(mAppBounds, mAppInsets);
|
||||
|
||||
tvs.fullScreenProgress.value = 1;
|
||||
tvs.recentsViewScale.value = tvs.getFullScreenScale();
|
||||
tvs.apply(this);
|
||||
} finally {
|
||||
helper.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceTransaction createSurfaceParams(BuilderProxy proxy) {
|
||||
RecordingSurfaceTransaction transaction = new RecordingSurfaceTransaction();
|
||||
proxy.onBuildTargetParams(
|
||||
transaction.mockProperties, mock(RemoteAnimationTarget.class), this);
|
||||
return transaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applySurfaceParams(SurfaceTransaction params) {
|
||||
Assert.assertTrue(params instanceof RecordingSurfaceTransaction);
|
||||
MockProperties p = ((RecordingSurfaceTransaction) params).mockProperties;
|
||||
|
||||
// Verify that the task position remains the same
|
||||
RectF newAppBounds = new RectF(mAppBounds);
|
||||
p.matrix.mapRect(newAppBounds);
|
||||
Assert.assertThat(newAppBounds, new AlmostSame(mAppBounds));
|
||||
|
||||
System.err.println("Bounds mapped: " + mAppBounds + " => " + newAppBounds);
|
||||
}
|
||||
}
|
||||
|
||||
private static class AlmostSame extends TypeSafeMatcher<RectF> {
|
||||
|
||||
// Allow .1% error margin to account for float to int conversions
|
||||
private final float mErrorFactor = .001f;
|
||||
private final Rect mExpected;
|
||||
|
||||
AlmostSame(Rect expected) {
|
||||
mExpected = expected;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean matchesSafely(RectF item) {
|
||||
float errorWidth = mErrorFactor * mExpected.width();
|
||||
float errorHeight = mErrorFactor * mExpected.height();
|
||||
return Math.abs(item.left - mExpected.left) < errorWidth
|
||||
&& Math.abs(item.top - mExpected.top) < errorHeight
|
||||
&& Math.abs(item.right - mExpected.right) < errorWidth
|
||||
&& Math.abs(item.bottom - mExpected.bottom) < errorHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendValue(mExpected);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user