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

Commit d3272907 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Removing UI dependency from LauncherModel in case of 2-panel layout" into sc-v2-dev

parents c48e4fa6 12e3f1f2
Loading
Loading
Loading
Loading
+0 −9
Original line number Diff line number Diff line
@@ -34,7 +34,6 @@ import android.content.Context;
import android.os.Process;
import android.os.UserHandle;

import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.ComponentWithLabel;
@@ -42,7 +41,6 @@ import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
import com.android.launcher3.model.QuickstepModelDelegate.PredictorState;
import com.android.launcher3.shadows.ShadowDeviceFlag;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.LauncherModelHelper;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.PendingAddWidgetInfo;
@@ -76,7 +74,6 @@ public final class WidgetsPredicationUpdateTaskTest {
    private Context mContext;
    private LauncherModelHelper mModelHelper;
    private UserHandle mUserHandle;
    private InvariantDeviceProfile mTestProfile;

    @Mock
    private IconCache mIconCache;
@@ -92,7 +89,6 @@ public final class WidgetsPredicationUpdateTaskTest {
        mContext = RuntimeEnvironment.application;
        mModelHelper = new LauncherModelHelper();
        mUserHandle = Process.myUserHandle();
        mTestProfile = new InvariantDeviceProfile();
        // 2 widgets, app4/provider1 & app5/provider1, have already been added to the workspace.
        mModelHelper.initializeData("/widgets_predication_update_task_data.txt");

@@ -226,10 +222,5 @@ public final class WidgetsPredicationUpdateTaskTest {
        public void bindExtraContainerItems(FixedContainerItems item) {
            mRecommendedWidgets = item;
        }

        @Override
        public IntSet getPagesToBindSynchronously() {
            return IntSet.wrap(0);
        }
    }
}
+2 −1
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.shadows.ShadowLooperExecutor;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.LauncherLayoutBuilder;
import com.android.launcher3.util.LauncherModelHelper;
@@ -202,7 +203,7 @@ public class ModelMultiCallbacksTest {
        }

        @Override
        public IntSet getPagesToBindSynchronously() {
        public IntSet getPagesToBindSynchronously(IntArray orderedScreenIds) {
            return mPageToBindSync;
        }

+0 −224
Original line number Diff line number Diff line
/**
 * Copyright (C) 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.launcher3.util;

import android.os.Bundle;

import com.android.launcher3.LauncherPageRestoreHelper;
import com.android.launcher3.Workspace;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.when;

@RunWith(RobolectricTestRunner.class)
public class LauncherPageRestoreHelperTest {

    // Type: int
    private static final String RUNTIME_STATE_CURRENT_SCREEN = "launcher.current_screen";
    // Type: int
    private static final String RUNTIME_STATE_CURRENT_SCREEN_COUNT =
            "launcher.current_screen_count";

    private LauncherPageRestoreHelper mPageRestoreHelper;
    private Bundle mState;

    @Mock
    private Workspace mWorkspace;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        mPageRestoreHelper = new LauncherPageRestoreHelper(mWorkspace);
        mState = new Bundle();
    }

    @Test
    public void givenNoChildrenInWorkspace_whenSavePages_thenNothingSaved() {
        when(mWorkspace.getChildCount()).thenReturn(0);

        mPageRestoreHelper.savePagesToRestore(mState);

        assertFalse(mState.containsKey(RUNTIME_STATE_CURRENT_SCREEN_COUNT));
        assertFalse(mState.containsKey(RUNTIME_STATE_CURRENT_SCREEN));
    }

    @Test
    public void givenMultipleCurrentPages_whenSavePages_thenSavedCorrectly() {
        when(mWorkspace.getChildCount()).thenReturn(5);
        when(mWorkspace.getCurrentPage()).thenReturn(2);
        givenPanelCount(2);

        mPageRestoreHelper.savePagesToRestore(mState);

        assertEquals(5, mState.getInt(RUNTIME_STATE_CURRENT_SCREEN_COUNT));
        assertEquals(2, mState.getInt(RUNTIME_STATE_CURRENT_SCREEN));
    }

    @Test
    public void givenNullSavedState_whenRestorePages_thenReturnEmptyIntSet() {
        IntSet result = mPageRestoreHelper.getPagesToRestore(null);

        assertTrue(result.isEmpty());
    }

    @Test
    public void givenTotalPageCountMissing_whenRestorePages_thenReturnEmptyIntSet() {
        givenSavedCurrentPage(1);
        givenPanelCount(1);

        IntSet result = mPageRestoreHelper.getPagesToRestore(mState);

        assertTrue(result.isEmpty());
    }

    @Test
    public void givenCurrentPageMissing_whenRestorePages_thenReturnEmptyIntSet() {
        givenSavedPageCount(3);
        givenPanelCount(2);

        IntSet result = mPageRestoreHelper.getPagesToRestore(mState);

        assertTrue(result.isEmpty());
    }

    @Test
    public void givenOnePanel_whenRestorePages_thenReturnThatPage() {
        givenSavedCurrentPage(2);
        givenSavedPageCount(5);
        givenPanelCount(1);

        IntSet result = mPageRestoreHelper.getPagesToRestore(mState);

        assertEquals(1, result.size());
        assertEquals(2, result.getArray().get(0));
    }

    @Test
    public void givenTwoPanelOnFirstPages_whenRestorePages_thenReturnThosePages() {
        givenSavedCurrentPage(0, 1);
        givenSavedPageCount(2);
        givenPanelCount(2);

        IntSet result = mPageRestoreHelper.getPagesToRestore(mState);

        assertEquals(IntSet.wrap(0, 1), result);
    }

    @Test
    public void givenTwoPanelOnMiddlePages_whenRestorePages_thenReturnThosePages() {
        givenSavedCurrentPage(2, 3);
        givenSavedPageCount(5);
        givenPanelCount(2);

        IntSet result = mPageRestoreHelper.getPagesToRestore(mState);

        assertEquals(IntSet.wrap(2, 3), result);
    }

    @Test
    public void givenTwoPanelOnLastPage_whenRestorePages_thenReturnOnlyLastPage() {
        // The device has two panel home but the current page is the last page, so we don't have
        // a right panel, only the left one.
        givenSavedCurrentPage(2);
        givenSavedPageCount(3);
        givenPanelCount(2);

        IntSet result = mPageRestoreHelper.getPagesToRestore(mState);

        assertEquals(IntSet.wrap(2), result);
    }

    @Test
    public void givenOnlyOnePageAndPhoneFolding_whenRestorePages_thenReturnOnlyOnePage() {
        givenSavedCurrentPage(0);
        givenSavedPageCount(1);
        givenPanelCount(1);

        IntSet result = mPageRestoreHelper.getPagesToRestore(mState);

        assertEquals(IntSet.wrap(0), result);
    }

    @Test
    public void givenPhoneFolding_whenRestorePages_thenReturnOnlyTheFirstCurrentPage() {
        givenSavedCurrentPage(2, 3);
        givenSavedPageCount(4);
        givenPanelCount(1);

        IntSet result = mPageRestoreHelper.getPagesToRestore(mState);

        assertEquals(IntSet.wrap(2), result);
    }

    @Test
    public void givenPhoneUnfolding_whenRestorePages_thenReturnCurrentPagePlusTheNextOne() {
        givenSavedCurrentPage(2);
        givenSavedPageCount(4);
        givenPanelCount(2);

        IntSet result = mPageRestoreHelper.getPagesToRestore(mState);

        assertEquals(IntSet.wrap(2, 3), result);
    }

    @Test
    public void givenPhoneUnfoldingOnLastPage_whenRestorePages_thenReturnOnlyLastPage() {
        givenSavedCurrentPage(4);
        givenSavedPageCount(5);
        givenPanelCount(2);

        IntSet result = mPageRestoreHelper.getPagesToRestore(mState);

        assertEquals(IntSet.wrap(4), result);
    }

    @Test
    public void givenOnlyOnePageAndPhoneUnfolding_whenRestorePages_thenReturnOnlyOnePage() {
        givenSavedCurrentPage(0);
        givenSavedPageCount(1);
        givenPanelCount(2);

        IntSet result = mPageRestoreHelper.getPagesToRestore(mState);

        assertEquals(IntSet.wrap(0), result);
    }

    private void givenPanelCount(int panelCount) {
        when(mWorkspace.getPanelCount()).thenReturn(panelCount);
        when(mWorkspace.getLeftmostVisiblePageForIndex(anyInt())).thenAnswer(invocation -> {
            int pageIndex = invocation.getArgument(0);
            return pageIndex * panelCount / panelCount;
        });
    }

    private void givenSavedPageCount(int pageCount) {
        mState.putInt(RUNTIME_STATE_CURRENT_SCREEN_COUNT, pageCount);
    }

    private void givenSavedCurrentPage(int... pages) {
        mState.putInt(RUNTIME_STATE_CURRENT_SCREEN, pages[0]);
    }
}
+13 −2
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;

import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.logging.StatsLogManager;
@@ -128,11 +129,21 @@ public class DeleteDropTarget extends ButtonDropTarget {
    public void completeDrop(DragObject d) {
        ItemInfo item = d.dragInfo;
        if (canRemove(item)) {
            int itemPage = mLauncher.getWorkspace().getCurrentPage();
            ItemInfo pageItem = item;
            if (item.container <= 0) {
                View v = mLauncher.getWorkspace().getHomescreenIconByItemId(item.container);
                if (v != null) {
                    pageItem = (ItemInfo) v.getTag();
                }
            }
            IntSet pageIds = pageItem.container == Favorites.CONTAINER_DESKTOP
                    ? IntSet.wrap(pageItem.screenId)
                    : mLauncher.getWorkspace().getCurrentPageScreenIds();

            onAccessibilityDrop(null, item);
            ModelWriter modelWriter = mLauncher.getModelWriter();
            Runnable onUndoClicked = () -> {
                mLauncher.setPagesToBindSynchronously(IntSet.wrap(itemPage));
                mLauncher.setPagesToBindSynchronously(pageIds);
                modelWriter.abortDelete();
                mLauncher.getStatsLogManager().logger().log(LAUNCHER_UNDO);
            };
+54 −25
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import static com.android.launcher3.LauncherState.NO_OFFSET;
import static com.android.launcher3.LauncherState.NO_SCALE;
import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.WorkspaceLayoutManager.LEFT_PANEL_ID;
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.getSupportedActions;
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_LAUNCHER_LOAD;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
@@ -259,6 +260,8 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
    private static final String RUNTIME_STATE_PENDING_ACTIVITY_RESULT = "launcher.activity_result";
    // Type: SparseArray<Parcelable>
    private static final String RUNTIME_STATE_WIDGET_PANEL = "launcher.widget_panel";
    // Type int[]
    private static final String RUNTIME_STATE_CURRENT_SCREEN_IDS = "launcher.current_screen_ids";

    public static final String ON_CREATE_EVT = "Launcher.onCreate";
    public static final String ON_START_EVT = "Launcher.onStart";
@@ -287,8 +290,6 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
    private WidgetManagerHelper mAppWidgetManager;
    private LauncherAppWidgetHost mAppWidgetHost;

    private LauncherPageRestoreHelper mPageRestoreHelper;

    private final int[] mTmpAddItemCellCoordinates = new int[2];

    @Thunk
@@ -325,7 +326,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
    private PopupDataProvider mPopupDataProvider;

    private IntSet mSynchronouslyBoundPages = new IntSet();
    private IntSet mPagesToBindSynchronously = new IntSet();
    @NonNull private IntSet mPagesToBindSynchronously = new IntSet();

    // We only want to get the SharedPreferences once since it does an FS stat each time we get
    // it from the context.
@@ -460,9 +461,11 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
        restoreState(savedInstanceState);
        mStateManager.reapplyState();

        mPageRestoreHelper = new LauncherPageRestoreHelper(mWorkspace);
        if (savedInstanceState != null) {
            mPagesToBindSynchronously = mPageRestoreHelper.getPagesToRestore(savedInstanceState);
            int[] pageIds = savedInstanceState.getIntArray(RUNTIME_STATE_CURRENT_SCREEN_IDS);
            if (pageIds != null) {
                mPagesToBindSynchronously = IntSet.wrap(pageIds);
            }
        }

        if (!mModel.addCallbacksAndLoad(this)) {
@@ -1188,7 +1191,6 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
        // Until the workspace is bound, ensure that we keep the wallpaper offset locked to the
        // default state, otherwise we will update to the wrong offsets in RTL
        mWorkspace.lockWallpaperToDefaultPage();
        mWorkspace.bindAndInitLeftPanel();
        mWorkspace.bindAndInitFirstWorkspaceScreen(null /* recycled qsb */);
        mDragController.addDragListener(mWorkspace);

@@ -1586,14 +1588,19 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
    public void onRestoreInstanceState(Bundle state) {
        super.onRestoreInstanceState(state);
        if (mSynchronouslyBoundPages != null) {
            mSynchronouslyBoundPages.forEach(page -> mWorkspace.restoreInstanceStateForChild(page));
            mSynchronouslyBoundPages.forEach(screenId -> {
                int pageIndex = mWorkspace.getPageIndexForScreenId(screenId);
                if (pageIndex != PagedView.INVALID_PAGE) {
                    mWorkspace.restoreInstanceStateForChild(pageIndex);
                }
            });
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        mPageRestoreHelper.savePagesToRestore(outState);

        outState.putIntArray(RUNTIME_STATE_CURRENT_SCREEN_IDS,
                mWorkspace.getCurrentPageScreenIds().getArray().toArray());
        outState.putInt(RUNTIME_STATE, mStateManager.getState().ordinal);

        AbstractFloatingView widgets = AbstractFloatingView
@@ -2081,18 +2088,42 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
        mPagesToBindSynchronously = pages;
    }

    /**
     * Implementation of the method from LauncherModel.Callbacks.
     */
    @Override
    public IntSet getPagesToBindSynchronously() {
        if (mPagesToBindSynchronously != null && !mPagesToBindSynchronously.isEmpty()) {
            return mPagesToBindSynchronously;
        } else if (mWorkspace != null) {
            return mWorkspace.getVisiblePageIndices();
    public IntSet getPagesToBindSynchronously(IntArray orderedScreenIds) {
        IntSet visibleIds = mPagesToBindSynchronously.isEmpty()
                ? mWorkspace.getCurrentPageScreenIds() : mPagesToBindSynchronously;
        IntArray actualIds = new IntArray();

        if (mDeviceProfile.isTwoPanels) {
            actualIds.add(LEFT_PANEL_ID);
        } else {
            return new IntSet();
            visibleIds.remove(LEFT_PANEL_ID);
        }
        IntSet result = new IntSet();
        if (visibleIds.isEmpty()) {
            return result;
        }
        for (int id : orderedScreenIds.toArray()) {
            if (id != LEFT_PANEL_ID) {
                actualIds.add(id);
            }
        }
        int firstId = visibleIds.getArray().get(0);
        if (actualIds.contains(firstId)) {
            result.add(firstId);

            if (mDeviceProfile.isTwoPanels) {
                int index = actualIds.indexOf(firstId);
                int nextIndex = ((int) (index / 2)) * 2;
                if (nextIndex == index) {
                    nextIndex++;
                }
                if (nextIndex < actualIds.size()) {
                    result.add(actualIds.get(nextIndex));
                }
            }
        }
        return result;
    }

    /**
@@ -2143,7 +2174,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
        // Make sure the first screen is at the start if there's no widget panel,
        // or on the second place if the first is the widget panel
        boolean isLeftPanelShown =
                mWorkspace.mWorkspaceScreens.containsKey(Workspace.LEFT_PANEL_ID);
                mWorkspace.mWorkspaceScreens.containsKey(LEFT_PANEL_ID);
        int firstScreenPosition = isLeftPanelShown && orderedScreenIds.size() > 1 ? 1 : 0;

        if (FeatureFlags.QSB_ON_FIRST_SCREEN &&
@@ -2171,7 +2202,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
                continue;
            }

            if (screenId == Workspace.LEFT_PANEL_ID) {
            if (screenId == LEFT_PANEL_ID) {
                // No need to bind the left panel, as its always bound.
                continue;
            }
@@ -2252,7 +2283,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
            }

            // Skip if the item is on the left widget panel but the panel is not shown
            if (item.screenId == Workspace.LEFT_PANEL_ID && !getDeviceProfile().isTwoPanels) {
            if (item.screenId == LEFT_PANEL_ID && !getDeviceProfile().isTwoPanels) {
                continue;
            }

@@ -2555,9 +2586,6 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
    @Override
    public void onInitialBindComplete(IntSet boundPages, RunnableList pendingTasks) {
        mSynchronouslyBoundPages = boundPages;
        if (!boundPages.isEmpty()) {
            mWorkspace.setCurrentPage(boundPages.getArray().get(0));
        }
        mPagesToBindSynchronously = new IntSet();

        clearPendingBinds();
@@ -2598,7 +2626,8 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
        }

        int currentPage = pagesBoundFirst != null && !pagesBoundFirst.isEmpty()
                ? pagesBoundFirst.getArray().get(0) : PagedView.INVALID_PAGE;
                ? mWorkspace.getPageIndexForScreenId(pagesBoundFirst.getArray().get(0))
                : PagedView.INVALID_PAGE;
        // When undoing the removal of the last item on a page, return to that page.
        // Since we are just resetting the current page without user interaction,
        // override the previous page so we don't log the page switch.
Loading