Snap for 11641371 from 0ec7c1e4a8 to 24Q3-release

Change-Id: I468a7f5f952a2fd425003766731720cdb40953b8
This commit is contained in:
Android Build Coastguard Worker
2024-03-28 23:20:53 +00:00
28 changed files with 631 additions and 196 deletions
+5
View File
@@ -155,6 +155,11 @@ android_library {
"animationlib",
"SystemUI-statsd",
"launcher-testing-shared",
"androidx.lifecycle_lifecycle-common-java8",
"androidx.lifecycle_lifecycle-extensions",
"androidx.lifecycle_lifecycle-runtime-ktx",
"kotlinx_coroutines_android",
"kotlinx_coroutines",
"com_android_launcher3_flags_lib",
"com_android_wm_shell_flags_lib",
"android.appwidget.flags-aconfig-java",
@@ -126,7 +126,7 @@
style="@style/GoOverviewActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableStart="@drawable/ic_save_app_pair"
android:drawableStart="@drawable/ic_save_app_pair_up_down"
android:text="@string/action_save_app_pair"
android:theme="@style/ThemeControlHighlightWorkspaceColor"
android:visibility="gone" />
@@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M13.329,2.305H4.242C2.751,2.305 1.542,3.514 1.542,5.005V13.005C1.542,14.496 2.751,15.705 4.242,15.705H7.875V19.011C7.875,20.502 9.084,21.711 10.575,21.711H19.662C21.153,21.711 22.362,20.502 22.362,19.011V10.011C22.362,8.52 21.153,7.311 19.662,7.311H16.029V5.005C16.029,3.514 14.821,2.305 13.329,2.305ZM14.329,7.311V5.005C14.329,4.452 13.882,4.005 13.329,4.005H4.242C3.69,4.005 3.242,4.452 3.242,5.005V13.005C3.242,13.557 3.69,14.005 4.242,14.005H7.875V10.011C7.875,8.52 9.084,7.311 10.575,7.311H14.329ZM9.575,14.005V10.011C9.575,9.611 9.81,9.266 10.15,9.106C10.285,9.037 10.438,8.999 10.6,8.999H19.687C20.239,8.999 20.687,9.447 20.687,9.999V18.999C20.687,19.399 20.452,19.744 20.113,19.904C19.977,19.972 19.824,20.011 19.662,20.011H10.575C10.023,20.011 9.575,19.563 9.575,19.011V15.705H9.6V14.005H9.575ZM15.542,11.996V14H17.588V15H15.542V16.996H14.542V15H12.464V14H14.542V11.996H15.542Z"
android:fillColor="#000000"
android:fillType="evenOdd"/>
</vector>
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2024 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M8.5,4.5H3.5C2.4,4.5 1.5,5.4 1.5,6.5V18.5C1.5,19.6 2.4,20.5 3.5,20.5H8.5C9.6,20.5 10.5,19.6 10.5,18.5V6.5C10.5,5.4 9.6,4.5 8.5,4.5ZM8.5,18.5H3.5V6.5H8.5V18.5ZM14.5,6.5H19.5V13.5H21.5V6.5C21.5,5.4 20.6,4.5 19.5,4.5H14.5C13.4,4.5 12.5,5.4 12.5,6.5V18.5C12.5,19.6 13.4,20.5 14.5,20.5H15.5V18.5H14.5V6.5ZM20.5,14.5V16.5H22.5V18.5H20.5V20.5H18.5V18.5H16.5V16.5H18.5V14.5H20.5Z"
android:fillColor="#48473A"
android:fillType="evenOdd"/>
</vector>
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2024 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M18,2L6,2C4.9,2 4,2.9 4,4L4,9C4,10.1 4.9,11 6,11L18,11C19.1,11 20,10.1 20,9L20,4C20,2.9 19.1,2 18,2ZM18,9L6,9L6,4L18,4L18,9ZM18,13L6,13C4.9,13 4,13.9 4,15L4,20C4,21.1 4.9,22 6,22L13,22L13,20L6,20L6,15L18,15L18,16L20,16L20,15C20,13.9 19.1,13 18,13ZM16,17L18,17L18,19L20,19L20,21L18,21L18,23L16,23L16,21L14,21L14,19L16,19L16,17Z"
android:fillColor="#48473A"
android:fillType="evenOdd"/>
</vector>
@@ -23,6 +23,7 @@
android:id="@+id/action_buttons"
android:layout_width="match_parent"
android:layout_height="@dimen/overview_actions_height"
android:layout_gravity="bottom"
android:gravity="center_horizontal"
android:orientation="horizontal">
@@ -41,6 +41,8 @@
android:layout_marginStart="@dimen/task_menu_option_text_start_margin"
android:textSize="14sp"
android:textColor="?androidprv:attr/materialColorOnSurface"
android:focusable="false" />
android:focusable="false"
android:gravity="start"
android:ellipsize="end" />
</LinearLayout>
@@ -21,7 +21,7 @@ import androidx.annotation.Nullable;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.quickstep.SystemUiProxy;
import com.android.wm.shell.transition.IHomeTransitionListener;
import com.android.wm.shell.shared.IHomeTransitionListener;
/**
* Controls launcher response to home activity visibility changing.
@@ -32,6 +32,8 @@ import com.android.launcher3.views.ActivityContext;
import com.android.quickstep.util.BaseDepthController;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import java.util.concurrent.TimeUnit;
/**
* Definition for AllApps state
*/
@@ -39,6 +41,8 @@ public class AllAppsState extends LauncherState {
private static final int STATE_FLAGS =
FLAG_WORKSPACE_INACCESSIBLE | FLAG_CLOSE_POPUPS | FLAG_HOTSEAT_INACCESSIBLE;
private static final long BACK_CUJ_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5);
public AllAppsState(int id) {
super(id, LAUNCHER_STATE_ALLAPPS, STATE_FLAGS);
@@ -53,14 +57,33 @@ public class AllAppsState extends LauncherState {
}
@Override
public void onBackPressed(Launcher launcher) {
public void onBackStarted(Launcher launcher) {
// Because the back gesture can take longer time depending on when user release the finger,
// we pass BACK_CUJ_TIMEOUT_MS as timeout to the jank monitor.
InteractionJankMonitorWrapper.begin(launcher.getAppsView(),
Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK);
super.onBackPressed(launcher);
Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK, BACK_CUJ_TIMEOUT_MS);
super.onBackStarted(launcher);
}
@Override
protected void onBackPressCompleted(boolean success) {
public void onBackInvoked(Launcher launcher) {
// In predictive back swipe, onBackInvoked() will be called after onBackStarted().
// Because the 2nd InteractionJankMonitor.begin() will be ignore within timeout, it's safe
// to call InteractionJankMonitorWrapper.begin here.
InteractionJankMonitorWrapper.begin(launcher.getAppsView(),
Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK);
super.onBackInvoked(launcher);
}
/** Called when predictive back swipe is cancelled. */
@Override
public void onBackCancelled(Launcher launcher) {
super.onBackCancelled(launcher);
InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK);
}
@Override
protected void onBackAnimationCompleted(boolean success) {
if (success) {
// Animation was successful.
InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK);
@@ -60,7 +60,7 @@ public class OverviewModalTaskState extends OverviewState {
}
@Override
public void onBackPressed(Launcher launcher) {
public void onBackInvoked(Launcher launcher) {
launcher.getStateManager().goToState(LauncherState.OVERVIEW);
}
@@ -199,7 +199,7 @@ public class OverviewState extends LauncherState {
}
@Override
public void onBackPressed(Launcher launcher) {
public void onBackInvoked(Launcher launcher) {
RecentsView recentsView = launcher.getOverviewPanel();
TaskView taskView = recentsView.getRunningTaskView();
if (taskView != null) {
@@ -209,7 +209,7 @@ public class OverviewState extends LauncherState {
recentsView.snapToPage(recentsView.indexOfChild(taskView));
}
} else {
super.onBackPressed(launcher);
super.onBackInvoked(launcher);
}
}
@@ -81,6 +81,7 @@ class AllAppsActionManager(
}
fun onDestroy() {
isActionRegistered = false
context
.getSystemService(AccessibilityManager::class.java)
?.unregisterSystemAction(
@@ -91,13 +91,13 @@ import com.android.wm.shell.draganddrop.IDragAndDrop;
import com.android.wm.shell.onehanded.IOneHanded;
import com.android.wm.shell.recents.IRecentTasks;
import com.android.wm.shell.recents.IRecentTasksListener;
import com.android.wm.shell.shared.IHomeTransitionListener;
import com.android.wm.shell.shared.IShellTransitions;
import com.android.wm.shell.splitscreen.ISplitScreen;
import com.android.wm.shell.splitscreen.ISplitScreenListener;
import com.android.wm.shell.splitscreen.ISplitSelectListener;
import com.android.wm.shell.startingsurface.IStartingWindow;
import com.android.wm.shell.startingsurface.IStartingWindowListener;
import com.android.wm.shell.transition.IHomeTransitionListener;
import com.android.wm.shell.transition.IShellTransitions;
import com.android.wm.shell.util.GroupedRecentTaskInfo;
import java.io.PrintWriter;
@@ -136,8 +136,9 @@ public interface TaskShortcutFactory {
class SaveAppPairSystemShortcut extends SystemShortcut<BaseDraggingActivity> {
private final GroupedTaskView mTaskView;
public SaveAppPairSystemShortcut(BaseDraggingActivity activity, GroupedTaskView taskView) {
super(R.drawable.ic_save_app_pair, R.string.save_app_pair, activity,
public SaveAppPairSystemShortcut(BaseDraggingActivity activity, GroupedTaskView taskView,
int iconResId) {
super(iconResId, R.string.save_app_pair, activity,
taskView.getItemInfo(), taskView);
mTaskView = taskView;
}
@@ -342,8 +343,12 @@ public interface TaskShortcutFactory {
return null;
}
int iconResId = deviceProfile.isLeftRightSplit
? R.drawable.ic_save_app_pair_left_right
: R.drawable.ic_save_app_pair_up_down;
return Collections.singletonList(
new SaveAppPairSystemShortcut(activity, (GroupedTaskView) taskView));
new SaveAppPairSystemShortcut(activity, (GroupedTaskView) taskView, iconResId));
}
@Override
@@ -135,9 +135,9 @@ import com.android.wm.shell.desktopmode.IDesktopMode;
import com.android.wm.shell.draganddrop.IDragAndDrop;
import com.android.wm.shell.onehanded.IOneHanded;
import com.android.wm.shell.recents.IRecentTasks;
import com.android.wm.shell.shared.IShellTransitions;
import com.android.wm.shell.splitscreen.ISplitScreen;
import com.android.wm.shell.startingsurface.IStartingWindow;
import com.android.wm.shell.transition.IShellTransitions;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -442,8 +442,10 @@ public class TouchInteractionService extends Service {
/** Refreshes the current overview target. */
public void refreshOverviewTarget() {
executeForTouchInteractionService(tis -> tis.onOverviewTargetChange(
tis.mOverviewComponentObserver.isHomeAndOverviewSame()));
executeForTouchInteractionService(tis -> {
tis.mAllAppsActionManager.onDestroy();
tis.onOverviewTargetChange(tis.mOverviewComponentObserver.isHomeAndOverviewSame());
});
}
}
@@ -20,7 +20,6 @@ import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
@@ -43,8 +42,6 @@ import com.android.quickstep.util.LayoutUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.stream.Collectors;
/**
* View for showing action buttons in Overview
@@ -297,17 +294,6 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
int desiredVisibility = mSplitButtonHiddenFlags == 0 ? VISIBLE : GONE;
mSplitButton.setVisibility(desiredVisibility);
findViewById(R.id.action_split_space).setVisibility(desiredVisibility);
String callStack = Arrays.stream(
Log.getStackTraceString(new Exception("thread stacktrace"))
.split("\\n"))
.limit(5)
.skip(1) // Removes the line "java.lang.Exception: thread stacktrace"
.collect(Collectors.joining("\n"));
Log.d("b/321291049", "updateSplitButtonHiddenFlags called with flag: " + flag
+ " enabled: " + enable
+ " visibility: " + desiredVisibility
+ " partial trace: \n" + callStack);
}
/**
@@ -407,7 +393,11 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
? R.drawable.ic_split_horizontal
: R.drawable.ic_split_vertical;
mSplitButton.setCompoundDrawablesRelativeWithIntrinsicBounds(splitIconRes, 0, 0, 0);
int appPairIconRes = dp.isLeftRightSplit
? R.drawable.ic_save_app_pair_left_right
: R.drawable.ic_save_app_pair_up_down;
mSaveAppPairButton.setCompoundDrawablesRelativeWithIntrinsicBounds(
R.drawable.ic_save_app_pair, 0, 0, 0);
appPairIconRes, 0, 0, 0);
}
}
@@ -135,8 +135,6 @@ import java.util.stream.Stream;
public class TaskView extends FrameLayout implements Reusable {
private static final String TAG = TaskView.class.getSimpleName();
private static final boolean DEBUG = false;
public static final int FLAG_UPDATE_ICON = 1;
public static final int FLAG_UPDATE_THUMBNAIL = FLAG_UPDATE_ICON << 1;
public static final int FLAG_UPDATE_CORNER_RADIUS = FLAG_UPDATE_THUMBNAIL << 1;
@@ -184,7 +182,7 @@ public class TaskView extends FrameLayout implements Reusable {
Collections.singletonList(new Rect());
public static final FloatProperty<TaskView> FOCUS_TRANSITION =
new FloatProperty<TaskView>("focusTransition") {
new FloatProperty<>("focusTransition") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setIconsAndBannersTransitionProgress(v, false /* invert */);
@@ -197,7 +195,7 @@ public class TaskView extends FrameLayout implements Reusable {
};
private static final FloatProperty<TaskView> SPLIT_SELECT_TRANSLATION_X =
new FloatProperty<TaskView>("splitSelectTranslationX") {
new FloatProperty<>("splitSelectTranslationX") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setSplitSelectTranslationX(v);
@@ -210,7 +208,7 @@ public class TaskView extends FrameLayout implements Reusable {
};
private static final FloatProperty<TaskView> SPLIT_SELECT_TRANSLATION_Y =
new FloatProperty<TaskView>("splitSelectTranslationY") {
new FloatProperty<>("splitSelectTranslationY") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setSplitSelectTranslationY(v);
@@ -223,7 +221,7 @@ public class TaskView extends FrameLayout implements Reusable {
};
private static final FloatProperty<TaskView> DISMISS_TRANSLATION_X =
new FloatProperty<TaskView>("dismissTranslationX") {
new FloatProperty<>("dismissTranslationX") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setDismissTranslationX(v);
@@ -236,7 +234,7 @@ public class TaskView extends FrameLayout implements Reusable {
};
private static final FloatProperty<TaskView> DISMISS_TRANSLATION_Y =
new FloatProperty<TaskView>("dismissTranslationY") {
new FloatProperty<>("dismissTranslationY") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setDismissTranslationY(v);
@@ -249,7 +247,7 @@ public class TaskView extends FrameLayout implements Reusable {
};
private static final FloatProperty<TaskView> TASK_OFFSET_TRANSLATION_X =
new FloatProperty<TaskView>("taskOffsetTranslationX") {
new FloatProperty<>("taskOffsetTranslationX") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setTaskOffsetTranslationX(v);
@@ -262,7 +260,7 @@ public class TaskView extends FrameLayout implements Reusable {
};
private static final FloatProperty<TaskView> TASK_OFFSET_TRANSLATION_Y =
new FloatProperty<TaskView>("taskOffsetTranslationY") {
new FloatProperty<>("taskOffsetTranslationY") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setTaskOffsetTranslationY(v);
@@ -275,7 +273,7 @@ public class TaskView extends FrameLayout implements Reusable {
};
private static final FloatProperty<TaskView> TASK_RESISTANCE_TRANSLATION_X =
new FloatProperty<TaskView>("taskResistanceTranslationX") {
new FloatProperty<>("taskResistanceTranslationX") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setTaskResistanceTranslationX(v);
@@ -288,7 +286,7 @@ public class TaskView extends FrameLayout implements Reusable {
};
private static final FloatProperty<TaskView> TASK_RESISTANCE_TRANSLATION_Y =
new FloatProperty<TaskView>("taskResistanceTranslationY") {
new FloatProperty<>("taskResistanceTranslationY") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setTaskResistanceTranslationY(v);
@@ -301,7 +299,7 @@ public class TaskView extends FrameLayout implements Reusable {
};
public static final FloatProperty<TaskView> GRID_END_TRANSLATION_X =
new FloatProperty<TaskView>("gridEndTranslationX") {
new FloatProperty<>("gridEndTranslationX") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setGridEndTranslationX(v);
@@ -314,7 +312,7 @@ public class TaskView extends FrameLayout implements Reusable {
};
public static final FloatProperty<TaskView> SNAPSHOT_SCALE =
new FloatProperty<TaskView>("snapshotScale") {
new FloatProperty<>("snapshotScale") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setSnapshotScale(v);
@@ -602,10 +600,7 @@ public class TaskView extends FrameLayout implements Reusable {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
computeAndSetIconTouchDelegate(mIconView, mIconCenterCoords, mIconTouchDelegate);
}
if (mIconTouchDelegate != null && mIconTouchDelegate.onTouchEvent(event)) {
return true;
}
return false;
return mIconTouchDelegate != null && mIconTouchDelegate.onTouchEvent(event);
}
protected void computeAndSetIconTouchDelegate(TaskViewIcon view, float[] tempCenterCoords,
@@ -647,9 +642,6 @@ public class TaskView extends FrameLayout implements Reusable {
/**
* Updates this task view to the given {@param task}.
*
* TODO(b/142282126) Re-evaluate if we need to pass in isMultiWindowMode after
* that issue is fixed
*/
public void bind(Task task, RecentsOrientedState orientedState) {
cancelPendingLoadTasks();
@@ -1594,19 +1586,6 @@ public class TaskView extends FrameLayout implements Reusable {
mEndQuickswitchCuj = endQuickswitchCuj;
}
private int getExpectedViewHeight(View view) {
int expectedHeight;
int h = view.getLayoutParams().height;
if (h > 0) {
expectedHeight = h;
} else {
int m = MeasureSpec.makeMeasureSpec(MeasureSpec.EXACTLY - 1, MeasureSpec.AT_MOST);
view.measure(m, m);
expectedHeight = view.getMeasuredHeight();
}
return expectedHeight;
}
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
+10 -1
View File
@@ -660,6 +660,11 @@ public class Launcher extends StatefulActivity<LauncherState>
// #5 state handler
return new OnBackAnimationCallback() {
@Override
public void onBackStarted(BackEvent backEvent) {
Launcher.this.onBackStarted();
}
@Override
public void onBackInvoked() {
onStateBack();
@@ -2063,8 +2068,12 @@ public class Launcher extends StatefulActivity<LauncherState>
getOnBackAnimationCallback().onBackInvoked();
}
protected void onBackStarted() {
mStateManager.getState().onBackStarted(this);
}
protected void onStateBack() {
mStateManager.getState().onBackPressed(this);
mStateManager.getState().onBackInvoked(this);
}
protected void onScreenOnChanged(boolean isOn) {
+14 -5
View File
@@ -424,20 +424,29 @@ public abstract class LauncherState implements BaseState<LauncherState> {
return TestProtocol.stateOrdinalToString(ordinal);
}
public void onBackPressed(Launcher launcher) {
/** Called when predictive back gesture is started. */
public void onBackStarted(Launcher launcher) {}
/**
* Called when back action is invoked. This can happen when:
* 1. back button is pressed in 3-button navigation.
* 2. when back is committed during back swiped (predictive or non-predictive).
* 3. when we programmatically perform back action.
*/
public void onBackInvoked(Launcher launcher) {
if (this != NORMAL) {
StateManager<LauncherState> lsm = launcher.getStateManager();
LauncherState lastState = lsm.getLastState();
lsm.goToState(lastState, forEndCallback(this::onBackPressCompleted));
lsm.goToState(lastState, forEndCallback(this::onBackAnimationCompleted));
}
}
/**
* To be called if back press is completed in a launcher state.
* To be called if back animation is completed in a launcher state.
*
* @param success whether back press animation was successful or canceled.
* @param success whether back animation was successful or canceled.
*/
protected void onBackPressCompleted(boolean success) {
protected void onBackAnimationCompleted(boolean success) {
// Do nothing. To be overridden by child class.
}
@@ -397,11 +397,6 @@ public final class FeatureFlags {
+ "waiting for SystemUI and then merging the SystemUI progress whenever we "
+ "start receiving the events");
// TODO(Block 24): Clean up flags
public static final BooleanFlag ENABLE_NEW_MIGRATION_LOGIC = getDebugFlag(270393455,
"ENABLE_NEW_MIGRATION_LOGIC", ENABLED,
"Enable the new grid migration logic, keeping pages when src < dest");
// TODO(Block 25): Clean up flags
public static final BooleanFlag ENABLE_NEW_GESTURE_NAV_TUTORIAL = getDebugFlag(270396257,
"ENABLE_NEW_GESTURE_NAV_TUTORIAL", ENABLED,
@@ -156,11 +156,11 @@ public class DeviceGridState implements Comparable<DeviceGridState> {
}
public Integer getColumns() {
return Integer.parseInt(String.valueOf(mGridSizeString.charAt(0)));
return Integer.parseInt(String.valueOf(mGridSizeString.split(",")[0]));
}
public Integer getRows() {
return Integer.parseInt(String.valueOf(mGridSizeString.charAt(2)));
return Integer.parseInt(String.valueOf(mGridSizeString.split(",")[1]));
}
@Override
@@ -223,19 +223,13 @@ public class GridSizeMigrationUtil {
screens.add(screenId);
}
boolean preservePages = false;
if (screens.isEmpty() && FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC.get()) {
preservePages = destDeviceState.compareTo(srcDeviceState) >= 0
&& destDeviceState.getColumns() - srcDeviceState.getColumns() <= 2;
}
// Then we place the items on the screens
for (int screenId : screens) {
if (DEBUG) {
Log.d(TAG, "Migrating " + screenId);
}
solveGridPlacement(helper, srcReader,
destReader, screenId, trgX, trgY, workspaceToBeAdded, false);
destReader, screenId, trgX, trgY, workspaceToBeAdded);
if (workspaceToBeAdded.isEmpty()) {
break;
}
@@ -245,8 +239,8 @@ public class GridSizeMigrationUtil {
// any of the screens, in this case we add them to new screens until all of them are placed.
int screenId = destReader.mLastScreenId + 1;
while (!workspaceToBeAdded.isEmpty()) {
solveGridPlacement(helper, srcReader,
destReader, screenId, trgX, trgY, workspaceToBeAdded, preservePages);
solveGridPlacement(helper, srcReader, destReader, screenId, trgX, trgY,
workspaceToBeAdded);
screenId++;
}
@@ -348,7 +342,7 @@ public class GridSizeMigrationUtil {
private static void solveGridPlacement(@NonNull final DatabaseHelper helper,
@NonNull final DbReader srcReader, @NonNull final DbReader destReader,
final int screenId, final int trgX, final int trgY,
@NonNull final List<DbEntry> sortedItemsToPlace, final boolean matchingScreenIdOnly) {
@NonNull final List<DbEntry> sortedItemsToPlace) {
final GridOccupancy occupied = new GridOccupancy(trgX, trgY);
final Point trg = new Point(trgX, trgY);
final Point next = new Point(0, screenId == 0
@@ -366,8 +360,6 @@ public class GridSizeMigrationUtil {
Iterator<DbEntry> iterator = sortedItemsToPlace.iterator();
while (iterator.hasNext()) {
final DbEntry entry = iterator.next();
if (matchingScreenIdOnly && entry.screenId < screenId) continue;
if (matchingScreenIdOnly && entry.screenId > screenId) break;
if (entry.minSpanX > trgX || entry.minSpanY > trgY) {
iterator.remove();
continue;
@@ -435,7 +427,8 @@ public class GridSizeMigrationUtil {
}
}
protected static class DbReader {
@VisibleForTesting
public static class DbReader {
private final SQLiteDatabase mDb;
private final String mTableName;
@@ -446,7 +439,7 @@ public class GridSizeMigrationUtil {
private final Map<Integer, ArrayList<DbEntry>> mWorkspaceEntriesByScreenId =
new ArrayMap<>();
DbReader(SQLiteDatabase db, String tableName, Context context,
public DbReader(SQLiteDatabase db, String tableName, Context context,
Set<String> validPackages) {
mDb = db;
mTableName = tableName;
+1
View File
@@ -86,6 +86,7 @@ android_library {
"mockito-target-extended-minus-junit4",
"launcher_log_protos_lite",
"truth",
"kotlinx_coroutines_test",
"platform-test-rules",
"testables",
"com_android_launcher3_flags_lib",
@@ -21,6 +21,13 @@ import java.util.Random
/** Generates a random CellLayoutBoard. */
open class RandomBoardGenerator(generator: Random) : DeterministicRandomGenerator(generator) {
companion object {
// This is the max number of widgets because we encode the widgets as letters A-Z and we
// already have some of those letter used by other things so 22 is a safe number
val MAX_NUMBER_OF_WIDGETS = 22
}
/**
* @param remainingEmptySpaces the maximum number of spaces we will fill with icons and widgets
* meaning that if the number is 100 we will try to fill the board with at most 100 spaces
@@ -33,9 +40,9 @@ open class RandomBoardGenerator(generator: Random) : DeterministicRandomGenerato
}
protected fun fillBoard(
board: CellLayoutBoard,
area: Rect,
remainingEmptySpacesArg: Int
board: CellLayoutBoard,
area: Rect,
remainingEmptySpacesArg: Int
): CellLayoutBoard {
var remainingEmptySpaces = remainingEmptySpacesArg
if (area.height() * area.width() <= 0) return board
@@ -45,11 +52,18 @@ open class RandomBoardGenerator(generator: Random) : DeterministicRandomGenerato
val y = area.top + getRandom(0, area.height() - height)
if (remainingEmptySpaces > 0) {
remainingEmptySpaces -= width * height
} else if (board.widgets.size <= 22 && width * height > 1) {
}
if (board.widgets.size <= MAX_NUMBER_OF_WIDGETS && width * height > 1) {
board.addWidget(x, y, width, height)
} else {
board.addIcon(x, y)
}
if (remainingEmptySpaces < 0) {
// optimization, no need to keep going
return board
}
fillBoard(board, Rect(area.left, area.top, area.right, y), remainingEmptySpaces)
fillBoard(board, Rect(area.left, y, x, area.bottom), remainingEmptySpaces)
fillBoard(board, Rect(x, y + height, area.right, area.bottom), remainingEmptySpaces)
@@ -0,0 +1,160 @@
/*
* Copyright (C) 2024 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.celllayout.testgenerator
import android.graphics.Point
import com.android.launcher3.LauncherSettings
import com.android.launcher3.celllayout.board.CellLayoutBoard
import com.android.launcher3.model.data.LauncherAppWidgetInfo
import com.android.launcher3.model.gridmigration.WorkspaceItem
import java.util.Random
import java.util.concurrent.atomic.AtomicInteger
/**
* Generate a list of WorkspaceItem's for the given test case.
*
* @param repeatAfter a number after which we would repeat the same number of icons and widgets to
* account for cases where the user have the same item multiple times.
*/
fun generateItemsForTest(
testCase: GridMigrationUnitTestCase,
repeatAfter: Int
): List<WorkspaceItem> {
val id = AtomicInteger(0)
val widgetId = AtomicInteger(LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - 1)
val boards = testCase.boards
// Repeat the same appWidgetProvider and intent to have repeating widgets and icons and test
// that case too
val getIntent = { i: Int -> "Intent ${i % repeatAfter}" }
val getProvider = { i: Int -> "com.test/test.Provider${i % repeatAfter}" }
val hotseatEntries =
(0 until boards[0].width).map {
WorkspaceItem(
x = it,
y = 0,
spanX = 1,
spanY = 1,
id = id.getAndAdd(1),
screenId = it,
title = "Hotseat ${id.get()}",
appWidgetId = -1,
appWidgetProvider = "Hotseat icons don't have a provider",
intent = getIntent(id.get()),
type = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION,
container = LauncherSettings.Favorites.CONTAINER_HOTSEAT
)
}
var widgetEntries =
boards
.flatMapIndexed { i, board -> board.widgets.map { Pair(i, it) } }
.map {
WorkspaceItem(
x = it.second.cellX,
y = it.second.cellY,
spanX = it.second.spanX,
spanY = it.second.spanY,
id = id.getAndAdd(1),
screenId = it.first,
title = "Title Widget ${id.get()}",
appWidgetId = widgetId.getAndAdd(-1),
appWidgetProvider = getProvider(id.get()),
intent = "Widgets don't have intent",
type = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET,
container = LauncherSettings.Favorites.CONTAINER_DESKTOP
)
}
widgetEntries = widgetEntries.filter { it.appWidgetProvider.contains("Provider4") }
val iconEntries =
boards
.flatMapIndexed { i, board -> board.icons.map { Pair(i, it) } }
.map {
WorkspaceItem(
x = it.second.coord.x,
y = it.second.coord.y,
spanX = 1,
spanY = 1,
id = id.getAndAdd(1),
screenId = it.first,
title = "Title Icon ${id.get()}",
appWidgetId = -1,
appWidgetProvider = "Icons don't have providers",
intent = getIntent(id.get()),
type = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION,
container = LauncherSettings.Favorites.CONTAINER_DESKTOP
)
}
return widgetEntries + hotseatEntries // + iconEntries
}
data class GridMigrationUnitTestCase(
val boards: List<CellLayoutBoard>,
val srcSize: Point,
val targetSize: Point,
val seed: Long
)
class ValidGridMigrationTestCaseGenerator(private val generator: Random) :
DeterministicRandomGenerator(generator) {
companion object {
const val MAX_BOARD_SIZE = 12
const val MAX_BOARD_COUNT = 10
const val SEED = 10342
}
private fun generateBoards(
boardGenerator: RandomBoardGenerator,
width: Int,
height: Int,
boardCount: Int
): List<CellLayoutBoard> {
val boards = mutableListOf<CellLayoutBoard>()
for (i in 0 until boardCount) {
boards.add(
boardGenerator.generateBoard(
width,
height,
boardGenerator.getRandom(0, width * height)
)
)
}
return boards
}
fun generateTestCase(): GridMigrationUnitTestCase {
var seed = generator.nextLong()
val randomBoardGenerator = RandomBoardGenerator(Random(seed))
val width = randomBoardGenerator.getRandom(3, MAX_BOARD_SIZE)
val height = randomBoardGenerator.getRandom(3, MAX_BOARD_SIZE)
return GridMigrationUnitTestCase(
boards =
generateBoards(
boardGenerator = randomBoardGenerator,
width = width,
height = height,
boardCount = randomBoardGenerator.getRandom(3, MAX_BOARD_COUNT)
),
srcSize = Point(width, height),
targetSize =
Point(
randomBoardGenerator.getRandom(3, MAX_BOARD_SIZE),
randomBoardGenerator.getRandom(3, MAX_BOARD_SIZE)
),
seed = seed
)
}
}
@@ -28,7 +28,6 @@ import com.android.launcher3.InvariantDeviceProfile
import com.android.launcher3.LauncherPrefs
import com.android.launcher3.LauncherPrefs.Companion.WORKSPACE_SIZE
import com.android.launcher3.LauncherSettings.Favorites.*
import com.android.launcher3.config.FeatureFlags
import com.android.launcher3.model.GridSizeMigrationUtil.DbReader
import com.android.launcher3.pm.UserCache
import com.android.launcher3.provider.LauncherDbUtils
@@ -98,10 +97,7 @@ class GridSizeMigrationUtilTest {
modelHelper.destroy()
}
/**
* Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is not
* needed anymore
*/
/** Old migration logic, should be modified once is not needed anymore */
@Test
@Throws(Exception::class)
fun testMigration() {
@@ -208,10 +204,7 @@ class GridSizeMigrationUtilTest {
assertThat(locMap[testPackage9]).isEqualTo(Point(0, 2))
}
/**
* Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is not
* needed anymore
*/
/** Old migration logic, should be modified once is not needed anymore */
@Test
@Throws(Exception::class)
fun testMigrationBackAndForth() {
@@ -605,68 +598,6 @@ class GridSizeMigrationUtilTest {
c.close()
}
/**
* Migrating from a smaller grid to a large one should keep the pages if the column difference
* is less than 2
*/
@Test
@Throws(Exception::class)
fun migrateFromSmallerGridSmallDifference() {
enableNewMigrationLogic("4,4")
// Setup src grid
addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 2, testPackage1, 5, TMP_TABLE)
addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 3, testPackage2, 6, TMP_TABLE)
addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 3, 1, testPackage3, 7, TMP_TABLE)
addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 3, 2, testPackage4, 8, TMP_TABLE)
addItem(ITEM_TYPE_APPLICATION, 2, CONTAINER_DESKTOP, 3, 3, testPackage5, 9, TMP_TABLE)
idp.numDatabaseHotseatIcons = 4
idp.numColumns = 6
idp.numRows = 5
val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
val destReader = DbReader(db, TABLE_NAME, context, validPackages)
GridSizeMigrationUtil.migrate(
dbHelper,
srcReader,
destReader,
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
DeviceGridState(idp)
)
// Get workspace items
val c =
db.query(
TABLE_NAME,
arrayOf(INTENT, SCREEN),
"container=$CONTAINER_DESKTOP",
null,
null,
null,
null
)
?: throw IllegalStateException()
val intentIndex = c.getColumnIndex(INTENT)
val screenIndex = c.getColumnIndex(SCREEN)
// Get in which screen the icon is
val locMap = HashMap<String?, Int>()
while (c.moveToNext()) {
locMap[Intent.parseUri(c.getString(intentIndex), 0).getPackage()] =
c.getInt(screenIndex)
}
c.close()
assertThat(locMap.size).isEqualTo(5)
assertThat(locMap[testPackage1]).isEqualTo(0)
assertThat(locMap[testPackage2]).isEqualTo(0)
assertThat(locMap[testPackage3]).isEqualTo(1)
assertThat(locMap[testPackage4]).isEqualTo(1)
assertThat(locMap[testPackage5]).isEqualTo(2)
}
/**
* Migrating from a smaller grid to a large one should reflow the pages if the column difference
* is more than 2
@@ -0,0 +1,114 @@
/*
* Copyright (C) 2024 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.gridmigration
import android.content.ContentValues
import android.database.sqlite.SQLiteDatabase
import android.graphics.Point
import com.android.launcher3.LauncherSettings.Favorites
import com.android.launcher3.celllayout.board.CellLayoutBoard
class MockSet(override val size: Int) : Set<String> {
override fun contains(element: String): Boolean = true
override fun containsAll(elements: Collection<String>): Boolean = true
override fun isEmpty(): Boolean = false
override fun iterator(): Iterator<String> = listOf<String>().iterator()
}
fun itemListToBoard(itemsArg: List<WorkspaceItem>, boardSize: Point): List<CellLayoutBoard> {
val items = itemsArg.filter { it.container != Favorites.CONTAINER_HOTSEAT }
val boardList =
List(items.maxOf { it.screenId + 1 }) { CellLayoutBoard(boardSize.x, boardSize.y) }
items.forEach {
when (it.type) {
Favorites.ITEM_TYPE_FOLDER,
Favorites.ITEM_TYPE_APP_PAIR -> throw Exception("Not implemented")
Favorites.ITEM_TYPE_APPWIDGET ->
boardList[it.screenId].addWidget(it.x, it.y, it.spanX, it.spanY)
Favorites.ITEM_TYPE_APPLICATION -> boardList[it.screenId].addIcon(it.x, it.y)
}
}
return boardList
}
fun insertIntoDb(tableName: String, entry: WorkspaceItem, db: SQLiteDatabase) {
val values = ContentValues()
values.put(Favorites.SCREEN, entry.screenId)
values.put(Favorites.CELLX, entry.x)
values.put(Favorites.CELLY, entry.y)
values.put(Favorites.SPANX, entry.spanX)
values.put(Favorites.SPANY, entry.spanY)
values.put(Favorites.TITLE, entry.title)
values.put(Favorites.INTENT, entry.intent)
values.put(Favorites.APPWIDGET_PROVIDER, entry.appWidgetProvider)
values.put(Favorites.APPWIDGET_ID, entry.appWidgetId)
values.put(Favorites.CONTAINER, entry.container)
values.put(Favorites.ITEM_TYPE, entry.type)
values.put(Favorites._ID, entry.id)
db.insert(tableName, null, values)
}
fun readDb(tableName: String, db: SQLiteDatabase): List<WorkspaceItem> {
val result = mutableListOf<WorkspaceItem>()
val cursor = db.query(tableName, null, null, null, null, null, null)
val indexCellX: Int = cursor.getColumnIndexOrThrow(Favorites.CELLX)
val indexCellY: Int = cursor.getColumnIndexOrThrow(Favorites.CELLY)
val indexSpanX: Int = cursor.getColumnIndexOrThrow(Favorites.SPANX)
val indexSpanY: Int = cursor.getColumnIndexOrThrow(Favorites.SPANY)
val indexId: Int = cursor.getColumnIndexOrThrow(Favorites._ID)
val indexScreen: Int = cursor.getColumnIndexOrThrow(Favorites.SCREEN)
val indexTitle: Int = cursor.getColumnIndexOrThrow(Favorites.TITLE)
val indexAppWidgetId: Int = cursor.getColumnIndexOrThrow(Favorites.APPWIDGET_ID)
val indexWidgetProvider: Int = cursor.getColumnIndexOrThrow(Favorites.APPWIDGET_PROVIDER)
val indexIntent: Int = cursor.getColumnIndexOrThrow(Favorites.INTENT)
val indexItemType: Int = cursor.getColumnIndexOrThrow(Favorites.ITEM_TYPE)
val container: Int = cursor.getColumnIndexOrThrow(Favorites.CONTAINER)
while (cursor.moveToNext()) {
result.add(
WorkspaceItem(
x = cursor.getInt(indexCellX),
y = cursor.getInt(indexCellY),
spanX = cursor.getInt(indexSpanX),
spanY = cursor.getInt(indexSpanY),
id = cursor.getInt(indexId),
screenId = cursor.getInt(indexScreen),
title = cursor.getString(indexTitle),
appWidgetId = cursor.getInt(indexAppWidgetId),
appWidgetProvider = cursor.getString(indexWidgetProvider),
intent = cursor.getString(indexIntent),
type = cursor.getInt(indexItemType),
container = cursor.getInt(container)
)
)
}
return result
}
data class WorkspaceItem(
val x: Int,
val y: Int,
val spanX: Int,
val spanY: Int,
val id: Int,
val screenId: Int,
val title: String,
val appWidgetId: Int,
val appWidgetProvider: String,
val intent: String,
val type: Int,
val container: Int,
)
@@ -0,0 +1,173 @@
/*
* 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.gridmigration
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.graphics.Point
import android.os.Process
import android.util.Log
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.InvariantDeviceProfile
import com.android.launcher3.LauncherSettings.Favorites
import com.android.launcher3.celllayout.testgenerator.ValidGridMigrationTestCaseGenerator
import com.android.launcher3.celllayout.testgenerator.generateItemsForTest
import com.android.launcher3.model.DatabaseHelper
import com.android.launcher3.model.DeviceGridState
import com.android.launcher3.model.GridSizeMigrationUtil
import com.android.launcher3.pm.UserCache
import com.android.launcher3.provider.LauncherDbUtils
import com.android.launcher3.util.rule.TestStabilityRule
import com.android.launcher3.util.rule.TestStabilityRule.Stability
import java.util.Random
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
class ValidGridMigrationUnitTest {
companion object {
const val SEED = 1044542
const val REPEAT_AFTER = 10
const val TAG = "ValidGridMigrationUnitTest"
}
private lateinit var context: Context
@Before
fun setUp() {
context = InstrumentationRegistry.getInstrumentation().targetContext
}
private fun validate(
srcItems: List<WorkspaceItem>,
dstItems: List<WorkspaceItem>,
destinationSize: Point
) {
// This returns a map with the number of repeated elements
// ex { calculatorIcon : 6, weatherWidget : 2 }
val itemsToSet = { it: List<WorkspaceItem> ->
it.filter { it.container != Favorites.CONTAINER_HOTSEAT }
.groupingBy {
when (it.type) {
Favorites.ITEM_TYPE_FOLDER,
Favorites.ITEM_TYPE_APP_PAIR -> throw Exception("Not implemented")
Favorites.ITEM_TYPE_APPWIDGET -> it.appWidgetProvider
Favorites.ITEM_TYPE_APPLICATION -> it.intent
else -> it.title
}
}
.eachCount()
}
for (it in dstItems) {
assert((it.x in 0..destinationSize.x) && (it.y in 0..destinationSize.y)) {
"Item outside of the board size. Size = $destinationSize Item = $it"
}
assert(
(it.x + it.spanX in 0..destinationSize.x) &&
(it.y + it.spanY in 0..destinationSize.y)
) {
"Item doesn't fit in the grid. Size = $destinationSize Item = $it"
}
}
assert(itemsToSet(srcItems) == itemsToSet(dstItems)) {
"The srcItems do not match the dstItems src = $srcItems dst = $dstItems"
}
}
private fun addItemsToDb(db: SQLiteDatabase, tableName: String, items: List<WorkspaceItem>) {
LauncherDbUtils.SQLiteTransaction(db).use { transaction ->
items.forEach { insertIntoDb(tableName, it, transaction.db) }
transaction.commit()
}
}
private fun migrate(
srcItems: List<WorkspaceItem>,
srcSize: Point,
targetSize: Point
): List<WorkspaceItem> {
val userSerial = UserCache.INSTANCE[context].getSerialNumberForUser(Process.myUserHandle())
val dbHelper =
DatabaseHelper(
context,
null,
{ UserCache.INSTANCE.get(context).getSerialNumberForUser(it) },
{}
)
val srcTableName = Favorites.TMP_TABLE
val dstTableName = Favorites.TABLE_NAME
Favorites.addTableToDb(dbHelper.writableDatabase, userSerial, false, srcTableName)
addItemsToDb(dbHelper.writableDatabase, srcTableName, srcItems)
LauncherDbUtils.SQLiteTransaction(dbHelper.writableDatabase).use {
GridSizeMigrationUtil.migrate(
dbHelper,
GridSizeMigrationUtil.DbReader(it.db, srcTableName, context, MockSet(1)),
GridSizeMigrationUtil.DbReader(it.db, dstTableName, context, MockSet(1)),
targetSize.x,
targetSize,
DeviceGridState(
srcSize.x,
srcSize.y,
srcSize.x,
InvariantDeviceProfile.TYPE_PHONE,
srcTableName
),
DeviceGridState(
targetSize.x,
targetSize.y,
targetSize.x,
InvariantDeviceProfile.TYPE_PHONE,
dstTableName
)
)
it.commit()
}
return readDb(dstTableName, dbHelper.readableDatabase)
}
@Test
fun runTestCase() {
val caseGenerator = ValidGridMigrationTestCaseGenerator(Random(SEED.toLong()))
for (i in 0..50) {
val testCase = caseGenerator.generateTestCase()
Log.d(TAG, "Test case = $testCase")
val srcItemList = generateItemsForTest(testCase, REPEAT_AFTER)
val dstItemList = migrate(srcItemList, testCase.srcSize, testCase.targetSize)
validate(srcItemList, dstItemList, testCase.targetSize)
}
}
// This test takes about 4 minutes, there is no need to run it in presubmit.
@Stability(flavors = TestStabilityRule.LOCAL or TestStabilityRule.PLATFORM_POSTSUBMIT)
@Test
fun runExtensiveTestCases() {
val caseGenerator = ValidGridMigrationTestCaseGenerator(Random(SEED.toLong()))
for (i in 0..1000) {
val testCase = caseGenerator.generateTestCase()
Log.d(TAG, "Test case = $testCase")
val srcItemList = generateItemsForTest(testCase, REPEAT_AFTER)
val dstItemList = migrate(srcItemList, testCase.srcSize, testCase.targetSize)
validate(srcItemList, dstItemList, testCase.targetSize)
}
}
}