From 1baf08e5b7a045afc762ce315c9fbe74f7d7c28f Mon Sep 17 00:00:00 2001 From: Anushree Ganjam Date: Tue, 23 Jan 2024 17:29:09 -0800 Subject: [PATCH 01/14] Add logs for IME search button tap. Bug: 316779102 Flag: NA, Add logs Test: Manual Change-Id: I38af3b83e87afabe84807faccf5f8f3d080d93a2 --- .../launcher3/allapps/search/AllAppsSearchBarController.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java index 4427a49dab..f9d047b980 100644 --- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java +++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java @@ -20,6 +20,7 @@ import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.text.TextWatcher; import android.text.style.SuggestionSpan; +import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.View.OnFocusChangeListener; @@ -42,6 +43,7 @@ public class AllAppsSearchBarController implements TextWatcher, OnEditorActionListener, ExtendedEditText.OnBackKeyListener, OnFocusChangeListener { + private static final String TAG = "AllAppsSearchBarController"; protected ActivityContext mLauncher; protected SearchCallback mCallback; protected ExtendedEditText mInput; @@ -122,6 +124,7 @@ public class AllAppsSearchBarController public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if (actionId == EditorInfo.IME_ACTION_SEARCH || actionId == EditorInfo.IME_ACTION_GO) { + Log.i(TAG, "User tapped ime search button"); // selectFocusedView should return SearchTargetEvent that is passed onto onClick return mLauncher.getAppsView().getMainAdapterProvider().launchHighlightedItem(); } From 2d8be108565293a158714dbacf8acacafce6cd3a Mon Sep 17 00:00:00 2001 From: Sebastian Franco Date: Mon, 22 Jan 2024 14:25:24 -0800 Subject: [PATCH 02/14] Adding unit test to makeSpaceForHotseatMigration Flag: NA Bug: 318417510 Test: atest HotseatReorderUnitTest Change-Id: If4fe388d00138b2d43693df0cf79abb16f354291 --- tests/Android.bp | 1 + .../celllayout/board/CellLayoutBoard.java | 6 +- .../testgenerator/RandomBoardGenerator.kt | 6 +- .../celllayout/HotseatReorderUnitTest.kt | 179 ++++++++++++++++++ 4 files changed, 186 insertions(+), 6 deletions(-) create mode 100644 tests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt diff --git a/tests/Android.bp b/tests/Android.bp index 310e418e48..ed8609e3d0 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -176,6 +176,7 @@ android_library { name: "launcher-testing-shared", srcs: [ "multivalentTests/shared/com/android/launcher3/testing/shared/**/*.java", + "multivalentTests/shared/com/android/launcher3/testing/shared/**/*.kt" ], resource_dirs: [], manifest: "multivalentTests/shared/AndroidManifest.xml", diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/CellLayoutBoard.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/CellLayoutBoard.java index dbbdcf519a..62f2259ca3 100644 --- a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/CellLayoutBoard.java +++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/CellLayoutBoard.java @@ -66,7 +66,7 @@ public class CellLayoutBoard implements Comparable { } public CellLayoutBoard(int width, int height) { - mWidget = new char[width + 1][height + 1]; + mWidget = new char[width][height]; this.mWidth = width; this.mHeight = height; for (int x = 0; x < mWidget.length; x++) { @@ -371,8 +371,8 @@ public class CellLayoutBoard implements Comparable { s.append("\n"); maxX = Math.min(maxX, mWidget.length); maxY = Math.min(maxY, mWidget[0].length); - for (int y = 0; y <= maxY; y++) { - for (int x = 0; x <= maxX; x++) { + for (int y = 0; y < maxY; y++) { + for (int x = 0; x < maxX; x++) { s.append(mWidget[x][y]); } s.append('\n'); diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt index 770024fb5d..fcfb3dbc76 100644 --- a/tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt +++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt @@ -27,7 +27,7 @@ open class RandomBoardGenerator(generator: Random) : DeterministicRandomGenerato * usually less than 100. * @return a randomly generated board filled with icons and widgets. */ - open fun generateBoard(width: Int, height: Int, remainingEmptySpaces: Int): CellLayoutBoard? { + open fun generateBoard(width: Int, height: Int, remainingEmptySpaces: Int): CellLayoutBoard { val cellLayoutBoard = CellLayoutBoard(width, height) return fillBoard(cellLayoutBoard, Rect(0, 0, width, height), remainingEmptySpaces) } @@ -39,8 +39,8 @@ open class RandomBoardGenerator(generator: Random) : DeterministicRandomGenerato ): CellLayoutBoard { var remainingEmptySpaces = remainingEmptySpacesArg if (area.height() * area.width() <= 0) return board - val width = getRandom(1, area.width() - 1) - val height = getRandom(1, area.height() - 1) + val width = getRandom(1, area.width()) + val height = getRandom(1, area.height()) val x = area.left + getRandom(0, area.width() - width) val y = area.top + getRandom(0, area.height() - height) if (remainingEmptySpaces > 0) { diff --git a/tests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt b/tests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt new file mode 100644 index 0000000000..13dfd5eca8 --- /dev/null +++ b/tests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt @@ -0,0 +1,179 @@ +/* + * 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 + +import android.content.Context +import android.graphics.Point +import android.util.Log +import android.view.View +import androidx.core.view.get +import androidx.test.core.app.ApplicationProvider +import com.android.launcher3.CellLayout +import com.android.launcher3.celllayout.board.CellLayoutBoard +import com.android.launcher3.celllayout.board.IconPoint +import com.android.launcher3.celllayout.board.PermutedBoardComparator +import com.android.launcher3.celllayout.board.WidgetRect +import com.android.launcher3.celllayout.testgenerator.RandomBoardGenerator +import com.android.launcher3.util.ActivityContextWrapper +import com.android.launcher3.views.DoubleShadowBubbleTextView +import java.util.Random +import org.junit.Assert +import org.junit.Rule +import org.junit.Test + +private class HotseatReorderTestCase( + val startBoard: CellLayoutBoard, + val endBoard: CellLayoutBoard +) { + override fun toString(): String { + return "$startBoard#endBoard:\n$endBoard" + } +} + +class HotseatReorderUnitTest { + + private val applicationContext: Context = + ActivityContextWrapper(ApplicationProvider.getApplicationContext()) + + @JvmField @Rule var cellLayoutBuilder = UnitTestCellLayoutBuilderRule() + + /** + * This test generates random CellLayout configurations and then try to reorder it and makes + * sure the result is a valid board meaning it didn't remove any widget or icon. + */ + @Test + fun generateValidTests() { + val generator = Random(Companion.SEED.toLong()) + for (i in 0 until Companion.TOTAL_OF_CASES_GENERATED) { + // Using a new seed so that we can replicate the same test cases. + val seed = generator.nextInt() + Log.d(Companion.TAG, "Seed = $seed") + + val testCase: HotseatReorderTestCase = + generateRandomTestCase(RandomBoardGenerator(Random(seed.toLong()))) + Log.d(Companion.TAG, "testCase = $testCase") + + Assert.assertTrue( + "invalid case $i", + PermutedBoardComparator().compare(testCase.startBoard, testCase.endBoard) == 0 + ) + } + } + + private fun addViewInCellLayout( + cellLayout: CellLayout, + cellX: Int, + cellY: Int, + spanX: Int, + spanY: Int, + isWidget: Boolean + ) { + val cell = + if (isWidget) View(applicationContext) + else DoubleShadowBubbleTextView(applicationContext) + cell.layoutParams = CellLayoutLayoutParams(cellX, cellY, spanX, spanY) + cellLayout.addViewToCellLayout( + cell, + -1, + cell.id, + cell.layoutParams as CellLayoutLayoutParams, + true + ) + } + + private fun solve(board: CellLayoutBoard): CellLayout { + val cl = cellLayoutBuilder.createCellLayout(board.width, board.height, false) + // The views have to be sorted or the result can vary + board.icons + .map(IconPoint::getCoord) + .sortedWith( + Comparator.comparing { p: Any -> (p as Point).x } + .thenComparing { p: Any -> (p as Point).y } + ) + .forEach { p -> + addViewInCellLayout( + cellLayout = cl, + cellX = p.x, + cellY = p.y, + spanX = 1, + spanY = 1, + isWidget = false + ) + } + board.widgets + .sortedWith( + Comparator.comparing(WidgetRect::getCellX).thenComparing(WidgetRect::getCellY) + ) + .forEach { widget -> + addViewInCellLayout( + cl, + widget.cellX, + widget.cellY, + widget.spanX, + widget.spanY, + isWidget = true + ) + } + if (cl.makeSpaceForHotseatMigration(true)) { + commitTempPosition(cl) + } + return cl + } + + private fun commitTempPosition(cellLayout: CellLayout) { + val count = cellLayout.shortcutsAndWidgets.childCount + for (i in 0 until count) { + val params = cellLayout.shortcutsAndWidgets[i].layoutParams as CellLayoutLayoutParams + params.cellX = params.tmpCellX + params.cellY = params.tmpCellY + } + } + + private fun boardFromCellLayout(cellLayout: CellLayout): CellLayoutBoard { + val views = mutableListOf() + for (i in 0 until cellLayout.shortcutsAndWidgets.childCount) { + views.add(cellLayout.shortcutsAndWidgets.getChildAt(i)) + } + return CellLayoutTestUtils.viewsToBoard(views, cellLayout.countX, cellLayout.countY) + } + + private fun generateRandomTestCase( + boardGenerator: RandomBoardGenerator + ): HotseatReorderTestCase { + val width: Int = boardGenerator.getRandom(3, Companion.MAX_BOARD_SIZE) + val height: Int = boardGenerator.getRandom(3, Companion.MAX_BOARD_SIZE) + val targetWidth: Int = boardGenerator.getRandom(1, width - 2) + val targetHeight: Int = boardGenerator.getRandom(1, height - 2) + val board: CellLayoutBoard = + boardGenerator.generateBoard(width, height, targetWidth * targetHeight) + val finishBoard: CellLayoutBoard = boardFromCellLayout(solve(board)) + return HotseatReorderTestCase(board, finishBoard) + } + + companion object { + private const val MAX_BOARD_SIZE = 13 + + /** + * There is nothing special about this numbers, the random seed is just to be able to + * reproduce the test cases and the height and width is a random number similar to what + * users expect on their devices + */ + private const val SEED = -194162315 + private const val TOTAL_OF_CASES_GENERATED = 300 + private const val TAG = "HotseatReorderUnitTest" + } +} From 1784a329e622a7ab1ff19033fe65674bba3c2135 Mon Sep 17 00:00:00 2001 From: Vadim Tryshev Date: Thu, 1 Feb 2024 11:33:23 -0800 Subject: [PATCH 03/14] Adding text messages to some asserts in TaplAddConfigWidgetTest Bug: 187761685 Flag: N/A Test: presubmit Change-Id: Ia8164f60f49b377e41db72f97c4f90d167292574 --- .../launcher3/ui/widget/TaplAddConfigWidgetTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/src/com/android/launcher3/ui/widget/TaplAddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/TaplAddConfigWidgetTest.java index d96287f6f4..7aa26a1a50 100644 --- a/tests/src/com/android/launcher3/ui/widget/TaplAddConfigWidgetTest.java +++ b/tests/src/com/android/launcher3/ui/widget/TaplAddConfigWidgetTest.java @@ -161,11 +161,12 @@ public class TaplAddConfigWidgetTest extends AbstractLauncherUiTest { public int getWidgetId() throws InterruptedException { Intent intent = blockingGetExtraIntent(); - assertNotNull(intent); - assertEquals(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE, intent.getAction()); + assertNotNull("Null EXTRA_INTENT", intent); + assertEquals("Intent action is not ACTION_APPWIDGET_CONFIGURE", + AppWidgetManager.ACTION_APPWIDGET_CONFIGURE, intent.getAction()); int widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, LauncherAppWidgetInfo.NO_ID); - assertNotSame(widgetId, LauncherAppWidgetInfo.NO_ID); + assertNotSame("Widget id is NO_ID", widgetId, LauncherAppWidgetInfo.NO_ID); return widgetId; } } From 25ef2e1ecac3f3fffd669e9fa577fd0964c2f15d Mon Sep 17 00:00:00 2001 From: Rohit Goyal Date: Fri, 26 Jan 2024 02:18:44 +0530 Subject: [PATCH 04/14] UI Improvement: Do not add archived app icon to workspace when unarchival starts in case the icon already doesn't exist. Test: verified bugfix locally. Bug: 319213296 Flag: ACONFIG com.android.launcher3.enable_support_for_archiving DEVELOPMENT Change-Id: Iad3cc1a254b1543511976469c444eeaf869c7d50 --- src/com/android/launcher3/model/AddWorkspaceItemsTask.java | 6 ++++++ src/com/android/launcher3/model/ItemInstallQueue.java | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java index 5e86bd6b8a..96a8da97f3 100644 --- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java +++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java @@ -33,6 +33,7 @@ import com.android.launcher3.model.BgDataModel.Callbacks; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.model.data.WorkspaceItemFactory; import com.android.launcher3.model.data.WorkspaceItemInfo; @@ -102,6 +103,11 @@ public class AddWorkspaceItemsTask extends BaseModelUpdateTask { Objects.requireNonNull(item.getIntent()))) { continue; } + + if (item instanceof ItemInfoWithIcon + && ((ItemInfoWithIcon) item).isArchived()) { + continue; + } } if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) { diff --git a/src/com/android/launcher3/model/ItemInstallQueue.java b/src/com/android/launcher3/model/ItemInstallQueue.java index 9a3abd47fd..59f453a21c 100644 --- a/src/com/android/launcher3/model/ItemInstallQueue.java +++ b/src/com/android/launcher3/model/ItemInstallQueue.java @@ -18,10 +18,12 @@ package com.android.launcher3.model; import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID; +import static com.android.launcher3.Flags.enableSupportForArchiving; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT; import static com.android.launcher3.model.data.AppInfo.makeLaunchIntent; +import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import android.appwidget.AppWidgetManager; @@ -276,6 +278,7 @@ public class ItemInstallQueue { return intent; } + @SuppressWarnings("NewApi") public Pair getItemInfo(Context context) { switch (itemType) { case ITEM_TYPE_APPLICATION: { @@ -297,6 +300,9 @@ public class ItemInstallQueue { } else { lai = laiList.get(0); si.intent = makeLaunchIntent(lai); + if (enableSupportForArchiving() && lai.getActivityInfo().isArchived) { + si.runtimeStatusFlags |= FLAG_ARCHIVED; + } } LauncherAppState.getInstance(context).getIconCache() .getTitleAndIcon(si, () -> lai, usePackageIcon, false); From 1f265cc90783831a19f5369a30c6b598344d47b5 Mon Sep 17 00:00:00 2001 From: fbaron Date: Thu, 1 Feb 2024 10:29:30 -0800 Subject: [PATCH 05/14] Fix indexoutofbounds in Folder Flag: NONE Test: n/a Fix: 322875847 Change-Id: I14f6ebe135014c806aee310e5919a72a6e8820f7 --- src/com/android/launcher3/folder/Folder.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java index 7ae70e097f..2f3f029963 100644 --- a/src/com/android/launcher3/folder/Folder.java +++ b/src/com/android/launcher3/folder/Folder.java @@ -800,6 +800,14 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo return; } + int size = getIconsInReadingOrder().size(); + if (size <= 1) { + Log.d(TAG, "Couldn't animate folder closed because there's " + size + " icons"); + closeComplete(false); + post(this::announceAccessibilityChanges); + return; + } + mContent.completePendingPageChanges(); mContent.snapToPageImmediately(mContent.getDestinationPage()); From 2829c361f3790fe18655bfc47ffe6da1fea0f543 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 31 Jan 2024 10:43:45 -0800 Subject: [PATCH 06/14] Blocking gestureNav on taskFragments within the Launcher activity Bug: 273828110 Flag: aconfig use_activity_overlay disabled Test: Verified on device Change-Id: Ie812e17012feb8e99e06d0593207a87ef0c768e3 --- .../quickstep/TouchInteractionService.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index 55a7985598..79f9392a85 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -24,6 +24,7 @@ import static android.view.MotionEvent.ACTION_POINTER_UP; import static android.view.MotionEvent.ACTION_UP; import static com.android.launcher3.Flags.enableCursorHoverStates; +import static com.android.launcher3.Flags.useActivityOverlay; import static com.android.launcher3.Launcher.INTENT_ACTION_ALL_APPS_TOGGLE; import static com.android.launcher3.LauncherPrefs.backedUpItem; import static com.android.launcher3.MotionEventsUtils.isTrackpadMotionEvent; @@ -1148,6 +1149,14 @@ public class TouchInteractionService extends Service { boolean launcherResumedThroughShellTransition = gestureState.getActivityInterface().isResumed() && !previousGestureState.isRecentsAnimationRunning(); + // If a task fragment within Launcher is resumed + boolean launcherChildActivityResumed = useActivityOverlay() + && runningTask != null + && runningTask.isHomeTask() + && mOverviewComponentObserver.isHomeAndOverviewSame() + && !launcherResumedThroughShellTransition + && !previousGestureState.isRecentsAnimationRunning(); + if (gestureState.getActivityInterface().isInLiveTileMode()) { return createOverviewInputConsumer( previousGestureState, @@ -1174,9 +1183,11 @@ public class TouchInteractionService extends Service { ? "launcher resumed through a shell transition" : "forceOverviewInputConsumer == true")) .append(", trying to use overview input consumer")); - } else if (mDeviceState.isGestureBlockedTask(runningTask)) { + } else if (mDeviceState.isGestureBlockedTask(runningTask) || launcherChildActivityResumed) { return getDefaultInputConsumer(reasonString.append(SUBSTRING_PREFIX) - .append("is gesture-blocked task, trying to use default input consumer")); + .append(launcherChildActivityResumed + ? "is launcher child-task, trying to use default input consumer" + : "is gesture-blocked task, trying to use default input consumer")); } else { reasonString.append(SUBSTRING_PREFIX) .append("using OtherActivityInputConsumer"); From cc138663ca0aba05c289f5b9792ad409b1f891d0 Mon Sep 17 00:00:00 2001 From: Mady Mellor Date: Wed, 31 Jan 2024 13:37:24 -0800 Subject: [PATCH 07/14] Launcher: use aconfig flag for bubble bar Flag: ACONFIG com.android.wm.shell.enable_bubble_bar DISABLED Test: make & enable / disable flag to check if it works: adb shell device_config put multitasking com.android.wm.shell.enable_bubble_bar true Test: PlatformScenarioTests: android.platform.test.scenario.sysui.bubble.BubbleBarTest Bug: 286246694 Change-Id: I0820973848675e8596e0e1605c7e43158d870382 --- .../launcher3/taskbar/bubbles/BubbleBarController.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java index 5819bb31cb..6dc7db766e 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java @@ -71,6 +71,7 @@ import com.android.launcher3.taskbar.TaskbarControllers; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.Executors.SimpleThreadFactory; import com.android.quickstep.SystemUiProxy; +import com.android.wm.shell.Flags; import com.android.wm.shell.bubbles.IBubblesListener; import com.android.wm.shell.common.bubbles.BubbleBarUpdate; import com.android.wm.shell.common.bubbles.BubbleInfo; @@ -101,8 +102,8 @@ public class BubbleBarController extends IBubblesListener.Stub { * * @see #onTaskbarRecreated() */ - private static boolean sBubbleBarEnabled = - SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false); + private static boolean sBubbleBarEnabled = Flags.enableBubbleBar() + || SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false); /** Whether showing bubbles in the launcher bubble bar is enabled. */ public static boolean isBubbleBarEnabled() { @@ -111,8 +112,10 @@ public class BubbleBarController extends IBubblesListener.Stub { /** Re-reads the value of the flag from SystemProperties when taskbar is recreated. */ public static void onTaskbarRecreated() { - sBubbleBarEnabled = SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false); + sBubbleBarEnabled = Flags.enableBubbleBar() + || SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false); } + private static final int MASK_HIDE_BUBBLE_BAR = SYSUI_STATE_BOUNCER_SHOWING | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED From 387fea97317d5b2a3455ee37244bd44b1921eea7 Mon Sep 17 00:00:00 2001 From: Fengjiang Li Date: Wed, 20 Dec 2023 14:19:28 -0800 Subject: [PATCH 08/14] Update TaplAddWidgetTest#testResizeWidget() and WidgetResizeFrame#resize() API to pass launcher's cellBoarderSpace and use its height to expand widget To expand widget vertically, the drag distance has to be >= 0.66 * (cellHeight + cellBoarderSpace.y). The TAPL test should add cellBoarderSpace.y onto the vertical drag distance to make test less flaky. Bug: 291104076 Test: Postsubmit passed https://android-build.corp.google.com/builds/abtd/run/L49100030001703948 Flag: NA Change-Id: I602cf29b83df6875abd8eadfe255a2adb13f03cb --- .../android/launcher3/testing/TestInformationHandler.java | 6 ++++++ .../com/android/launcher3/testing/shared/TestProtocol.java | 1 + .../com/android/launcher3/tapl/LauncherInstrumentation.java | 5 +++++ .../tapl/com/android/launcher3/tapl/WidgetResizeFrame.java | 3 ++- 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java index ccff095c0e..8c938acbd4 100644 --- a/src/com/android/launcher3/testing/TestInformationHandler.java +++ b/src/com/android/launcher3/testing/TestInformationHandler.java @@ -153,6 +153,12 @@ public class TestInformationHandler implements ResourceBasedOverride { }, this::getCurrentActivity); } + case TestProtocol.REQUEST_CELL_LAYOUT_BOARDER_HEIGHT: { + response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, + mDeviceProfile.cellLayoutBorderSpacePx.y); + return response; + } + case TestProtocol.REQUEST_SYSTEM_GESTURE_REGION: { return getUIProperty(Bundle::putParcelable, activity -> { WindowInsetsCompat insets = WindowInsetsCompat.toWindowInsetsCompat( diff --git a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java index 3e188e6fb1..2f9945d17e 100644 --- a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java +++ b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java @@ -121,6 +121,7 @@ public final class TestProtocol { public static final String REQUEST_IS_TABLET = "is-tablet"; public static final String REQUEST_NUM_ALL_APPS_COLUMNS = "num-all-apps-columns"; public static final String REQUEST_IS_TWO_PANELS = "is-two-panel"; + public static final String REQUEST_CELL_LAYOUT_BOARDER_HEIGHT = "cell-layout-boarder-height"; public static final String REQUEST_START_DRAG_THRESHOLD = "start-drag-threshold"; public static final String REQUEST_SHELL_DRAG_READY = "shell-drag-ready"; public static final String REQUEST_GET_ACTIVITIES_CREATED_COUNT = diff --git a/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index fef93b7626..6c9f5ed620 100644 --- a/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -405,6 +405,11 @@ public final class LauncherInstrumentation { .getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD); } + int getCellLayoutBoarderHeight() { + return getTestInfo(TestProtocol.REQUEST_CELL_LAYOUT_BOARDER_HEIGHT) + .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD); + } + int getFocusedTaskHeightForTablet() { return getTestInfo(TestProtocol.REQUEST_GET_FOCUSED_TASK_HEIGHT_FOR_TABLET).getInt( TestProtocol.TEST_INFO_RESPONSE_FIELD); diff --git a/tests/multivalentTests/tapl/com/android/launcher3/tapl/WidgetResizeFrame.java b/tests/multivalentTests/tapl/com/android/launcher3/tapl/WidgetResizeFrame.java index d0573e077b..3895302794 100644 --- a/tests/multivalentTests/tapl/com/android/launcher3/tapl/WidgetResizeFrame.java +++ b/tests/multivalentTests/tapl/com/android/launcher3/tapl/WidgetResizeFrame.java @@ -57,7 +57,8 @@ public class WidgetResizeFrame { Rect originalWidgetSize = widget.getVisibleBounds(); Point targetStart = bottomResizeHandle.getVisibleCenter(); Point targetDest = bottomResizeHandle.getVisibleCenter(); - targetDest.offset(0, originalWidgetSize.height()); + targetDest.offset(0, + originalWidgetSize.height() + mLauncher.getCellLayoutBoarderHeight()); final long downTime = SystemClock.uptimeMillis(); mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, targetStart, From b9ba4b98137c91fc14abe81e88edddc09ea45041 Mon Sep 17 00:00:00 2001 From: Fengjiang Li Date: Thu, 1 Feb 2024 10:57:19 -0800 Subject: [PATCH 09/14] Fix small gap between widget resize frame and widget background. There is a 1dp gap on left/top/right/bottom between widget resize frame and widget background. Increasing the margin by 1dp will fill this gap. Fix: 291104076 Test: See https://b.corp.google.com/issues/291104076#comment9 Flag: NONE Change-Id: I471c27b8b5d59850a4bf342fc2d8fee50d6fd65d --- res/values/dimens.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 603e697395..b19ee0c41f 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -56,7 +56,7 @@ 13dp 24dp - 22dp + 23dp 24dp From c475f22d8b520440bbecbb18261bdb27e05f936e Mon Sep 17 00:00:00 2001 From: Rohit Goyal Date: Fri, 26 Jan 2024 02:17:05 +0530 Subject: [PATCH 10/14] UI Improvement: Persist archived app icon on workspace in case app uninstallation is cancelled. Test: verified bugfix locally. Bug: 319213296 Flag: ACONFIG com.android.launcher3.enable_support_for_archiving DEVELOPMENT Change-Id: Id9ba2ea833e8360ac8aa2c765beff402cff12ae2 --- .../launcher3/util/PackageManagerHelper.java | 12 ++- .../util/PackageManagerHelperTest.java | 83 +++++++++++++++++++ 2 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 tests/src/com/android/launcher3/util/PackageManagerHelperTest.java diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java index 2b5aaf5520..50d8886980 100644 --- a/src/com/android/launcher3/util/PackageManagerHelper.java +++ b/src/com/android/launcher3/util/PackageManagerHelper.java @@ -16,6 +16,8 @@ package com.android.launcher3.util; +import static com.android.launcher3.Flags.enableSupportForArchiving; + import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; @@ -112,8 +114,7 @@ public class PackageManagerHelper { @NonNull final UserHandle user, final int flags) { try { ApplicationInfo info = mLauncherApps.getApplicationInfo(packageName, flags, user); - return (info.flags & ApplicationInfo.FLAG_INSTALLED) == 0 || !info.enabled - ? null : info; + return !isPackageInstalledOrArchived(info) || !info.enabled ? null : info; } catch (PackageManager.NameNotFoundException e) { return null; } @@ -253,4 +254,11 @@ public class PackageManagerHelper { } return 100; } + + /** Returns true in case app is installed on the device or in archived state. */ + @SuppressWarnings("NewApi") + private boolean isPackageInstalledOrArchived(ApplicationInfo info) { + return (info.flags & ApplicationInfo.FLAG_INSTALLED) != 0 || ( + enableSupportForArchiving() && info.isArchived); + } } diff --git a/tests/src/com/android/launcher3/util/PackageManagerHelperTest.java b/tests/src/com/android/launcher3/util/PackageManagerHelperTest.java new file mode 100644 index 0000000000..d1da5f4f2d --- /dev/null +++ b/tests/src/com/android/launcher3/util/PackageManagerHelperTest.java @@ -0,0 +1,83 @@ +/* + * 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.util; + +import static com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.LauncherApps; +import android.content.pm.PackageManager; +import android.os.UserHandle; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; + +/** Unit tests for {@link PackageManagerHelper}. */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public final class PackageManagerHelperTest { + @Rule + public ExpectedException exception = ExpectedException.none(); + + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + + private static final String TEST_PACKAGE = "com.android.test.package"; + private static final int TEST_USER = 2; + + private Context mContext; + private LauncherApps mLauncherApps; + private PackageManagerHelper mPackageManagerHelper; + + @Before + public void setup() { + mContext = mock(Context.class); + mLauncherApps = mock(LauncherApps.class); + when(mContext.getSystemService(eq(LauncherApps.class))).thenReturn(mLauncherApps); + mPackageManagerHelper = new PackageManagerHelper(mContext); + } + + @Test + @RequiresFlagsEnabled(FLAG_ENABLE_SUPPORT_FOR_ARCHIVING) + public void getApplicationInfo_archivedApp_appInfoIsNotNull() + throws PackageManager.NameNotFoundException { + ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.isArchived = true; + when(mLauncherApps.getApplicationInfo(TEST_PACKAGE, 0 /* flags */, + UserHandle.of(TEST_USER))) + .thenReturn(applicationInfo); + + assertThat(mPackageManagerHelper.getApplicationInfo(TEST_PACKAGE, UserHandle.of(TEST_USER), + 0 /* flags */)) + .isNotNull(); + } +} From fee52acb29dd17013502b7d6fed75c55fafe001f Mon Sep 17 00:00:00 2001 From: samcackett Date: Wed, 31 Jan 2024 10:19:44 +0000 Subject: [PATCH 11/14] Fix issue with IconAppChipView animated states Cancel in progress animations and resume from previous position. Display TaskMenuView once. Fixes: 322813710 Test: Manual Flag: ACONFIG com.android.launcher3.enable_overview_icon_menu TEAMFOOD Change-Id: I73410d6116876ca83f3b16311d2e9eb372308295 --- .../quickstep/views/IconAppChipView.java | 33 +++++++++++++------ .../android/quickstep/views/TaskMenuView.java | 21 ++++++++---- .../com/android/quickstep/views/TaskView.java | 5 ++- 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/IconAppChipView.java b/quickstep/src/com/android/quickstep/views/IconAppChipView.java index ee09c4dedd..b064405ca5 100644 --- a/quickstep/src/com/android/quickstep/views/IconAppChipView.java +++ b/quickstep/src/com/android/quickstep/views/IconAppChipView.java @@ -86,6 +86,7 @@ public class IconAppChipView extends FrameLayout implements TaskViewIcon { private final int mMinIconBackgroundHeight; private final int mMaxIconBackgroundCornerRadius; private final float mMinIconBackgroundCornerRadius; + private AnimatorSet mAnimator; private int mMaxWidth = Integer.MAX_VALUE; @@ -315,11 +316,13 @@ public class IconAppChipView extends FrameLayout implements TaskViewIcon { } protected void revealAnim(boolean isRevealing) { + cancelInProgressAnimations(); + if (isRevealing) { boolean isRtl = isLayoutRtl(); bringToFront(); ((AnimatedVectorDrawable) mIconArrowView.getDrawable()).start(); - AnimatorSet anim = new AnimatorSet(); + mAnimator = new AnimatorSet(); float backgroundScaleY = mMaxIconBackgroundHeight / (float) mMinIconBackgroundHeight; float maxCornerSize = Math.min(mMaxIconBackgroundHeight / 2f, mMaxIconBackgroundCornerRadius); @@ -340,7 +343,7 @@ public class IconAppChipView extends FrameLayout implements TaskViewIcon { mIconTextMaxWidth + maxCornerSize); } }); - anim.playTogether( + mAnimator.playTogether( expandedTextRevealAnim, ObjectAnimator.ofFloat(mIconViewBackgroundCornersStart, SCALE_Y, backgroundScaleY), @@ -366,9 +369,9 @@ public class IconAppChipView extends FrameLayout implements TaskViewIcon { ObjectAnimator.ofFloat(mIconTextExpandedView, ALPHA, 1), ObjectAnimator.ofFloat(mIconArrowView, TRANSLATION_X, isRtl ? -arrowTranslationX : arrowTranslationX)); - anim.setDuration(MENU_BACKGROUND_REVEAL_DURATION); - anim.setInterpolator(EMPHASIZED); - anim.start(); + mAnimator.setDuration(MENU_BACKGROUND_REVEAL_DURATION); + mAnimator.setInterpolator(EMPHASIZED); + mAnimator.start(); } else { ((AnimatedVectorDrawable) mIconArrowView.getDrawable()).reverse(); float maxCornerSize = Math.min(mMaxIconBackgroundHeight / 2f, @@ -385,8 +388,8 @@ public class IconAppChipView extends FrameLayout implements TaskViewIcon { mIconTextExpandedView.getHeight() / 2f, 0); } }); - AnimatorSet anim = new AnimatorSet(); - anim.playTogether( + mAnimator = new AnimatorSet(); + mAnimator.playTogether( expandedTextClipAnim, ObjectAnimator.ofFloat(mIconViewBackgroundCornersStart, SCALE_X, 1), ObjectAnimator.ofFloat(mIconViewBackgroundCornersStart, SCALE_Y, 1), @@ -402,9 +405,9 @@ public class IconAppChipView extends FrameLayout implements TaskViewIcon { ObjectAnimator.ofFloat(mIconTextCollapsedView, ALPHA, 1), ObjectAnimator.ofFloat(mIconTextExpandedView, ALPHA, 0), ObjectAnimator.ofFloat(mIconArrowView, TRANSLATION_X, 0)); - anim.setDuration(MENU_BACKGROUND_HIDE_DURATION); - anim.setInterpolator(EMPHASIZED); - anim.start(); + mAnimator.setDuration(MENU_BACKGROUND_HIDE_DURATION); + mAnimator.setInterpolator(EMPHASIZED); + mAnimator.start(); } } @@ -424,6 +427,16 @@ public class IconAppChipView extends FrameLayout implements TaskViewIcon { mIconTextExpandedView.setAlpha(0); mIconArrowView.setTranslationX(0); ((AnimatedVectorDrawable) mIconArrowView.getDrawable()).reset(); + mAnimator = null; + } + + private void cancelInProgressAnimations() { + // We null the `AnimatorSet` because it holds references to the `Animators` which aren't + // expecting to be mutable and will cause a crash if they are re-used. + if (mAnimator != null && mAnimator.isStarted()) { + mAnimator.cancel(); + mAnimator = null; + } } @Override diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java index 77033b2fa2..3a4056afe4 100644 --- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java +++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java @@ -24,6 +24,7 @@ import static com.android.quickstep.views.TaskThumbnailView.DIM_ALPHA; import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Outline; import android.graphics.Rect; @@ -69,6 +70,8 @@ public class TaskMenuView extends AbstractFloatingView { private TextView mTaskName; @Nullable private AnimatorSet mOpenCloseAnimator; + @Nullable + private ValueAnimator mRevealAnimator; @Nullable private Runnable mOnClosingStartCallback; private TaskView mTaskView; private TaskIdAttributeContainer mTaskContainer; @@ -289,13 +292,18 @@ public class TaskMenuView extends AbstractFloatingView { private void animateOpenOrClosed(boolean closing) { if (mOpenCloseAnimator != null && mOpenCloseAnimator.isRunning()) { - mOpenCloseAnimator.end(); + mOpenCloseAnimator.cancel(); } mOpenCloseAnimator = new AnimatorSet(); - - final Animator revealAnimator = createOpenCloseOutlineProvider() - .createRevealAnimator(this, closing); - revealAnimator.setInterpolator(enableOverviewIconMenu() ? Interpolators.EMPHASIZED + // If we're opening, we just start from the beginning as a new `TaskMenuView` is created + // each time we do the open animation so there will never be a partial value here. + float revealAnimationStartProgress = 0f; + if (closing && mRevealAnimator != null) { + revealAnimationStartProgress = 1f - mRevealAnimator.getAnimatedFraction(); + } + mRevealAnimator = createOpenCloseOutlineProvider() + .createRevealAnimator(this, closing, revealAnimationStartProgress); + mRevealAnimator.setInterpolator(enableOverviewIconMenu() ? Interpolators.EMPHASIZED : Interpolators.DECELERATE); if (enableOverviewIconMenu()) { @@ -348,7 +356,7 @@ public class TaskMenuView extends AbstractFloatingView { mOpenCloseAnimator.playTogether(translationXAnim, menuTranslationXAnim); } - mOpenCloseAnimator.playTogether(revealAnimator, + mOpenCloseAnimator.playTogether(mRevealAnimator, ObjectAnimator.ofFloat( mTaskContainer.getThumbnailView(), DIM_ALPHA, closing ? 0 : TaskView.MAX_PAGE_SCRIM_ALPHA), @@ -377,6 +385,7 @@ public class TaskMenuView extends AbstractFloatingView { mIsOpen = false; resetOverviewIconMenu(); mActivity.getDragLayer().removeView(this); + mRevealAnimator = null; } private void resetOverviewIconMenu() { diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index f2c0286e60..65020bc762 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -1137,9 +1137,8 @@ public class TaskView extends FrameLayout implements Reusable { DeviceProfile dp = mActivity.getDeviceProfile(); if (enableOverviewIconMenu() && iconView instanceof IconAppChipView) { ((IconAppChipView) iconView).revealAnim(/* isRevealing= */ true); - return TaskMenuView.showForTask(menuContainer, () -> { - ((IconAppChipView) iconView).revealAnim(/* isRevealing= */ false); - }); + return TaskMenuView.showForTask(menuContainer, + () -> ((IconAppChipView) iconView).revealAnim(/* isRevealing= */ false)); } else if (dp.isTablet) { int alignedOptionIndex = 0; if (getRecentsView().isOnGridBottomRow(menuContainer.getTaskView()) && dp.isLandscape) { From ec52ed9f99f66a7bf3a866cca26142e8c38cd7fe Mon Sep 17 00:00:00 2001 From: Vinit Nayak Date: Tue, 23 Jan 2024 15:58:02 -0800 Subject: [PATCH 12/14] Intercept clicks for non-supported split targets on workspace * If we're in split selection state we disable the following - G icon on PSB - Lens icon on PSB - Smartspace - Widgets Bug: 295467097 Test: Enter split contextual and observe split instructions view going boing when tapping on unsupported target Flag: com.android.wm.shell.enable_split_contextual Change-Id: Ia7783472f3de9359c2784788be5f35596cbc8deb --- .../uioverrides/QuickstepInteractionHandler.java | 5 +---- .../launcher3/uioverrides/QuickstepLauncher.java | 14 ++++++++++++-- .../android/launcher3/views/ActivityContext.java | 13 +++++++++++++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java index 22f24f185a..039c0a0ad8 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java @@ -28,10 +28,8 @@ import android.util.Log; import android.util.Pair; import android.view.View; import android.widget.RemoteViews; -import android.widget.Toast; import android.window.SplashScreen; -import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.model.data.ItemInfo; @@ -63,8 +61,7 @@ class QuickstepInteractionHandler implements RemoteViews.InteractionHandler { // Log metric StatsLogManager.StatsLogger logger = mLauncher.getStatsLogManager().logger(); logger.log(LAUNCHER_SPLIT_WIDGET_ATTEMPT); - Toast.makeText(hostView.getContext(), R.string.split_widgets_not_supported, - Toast.LENGTH_SHORT).show(); + mLauncher.handleIncorrectSplitTargetSelection(); return true; } Pair options = remoteResponse.getLaunchOptions(view); diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index 32d10b04ef..ac0e53e3d2 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -36,6 +36,7 @@ import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK; import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT; import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent; +import static com.android.launcher3.config.FeatureFlags.enableSplitContextually; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP; import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID; import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition; @@ -676,7 +677,7 @@ public class QuickstepLauncher extends Launcher { splitSelectSource.alreadyRunningTaskId = taskWasFound ? foundTask.key.id : INVALID_TASK_ID; - if (FeatureFlags.enableSplitContextually()) { + if (enableSplitContextually()) { startSplitToHome(splitSelectSource); } else { recentsView.initiateSplitSelect(splitSelectSource); @@ -761,7 +762,7 @@ public class QuickstepLauncher extends Launcher { super.onPause(); - if (FeatureFlags.enableSplitContextually()) { + if (enableSplitContextually()) { // If Launcher pauses before both split apps are selected, exit split screen. if (!mSplitSelectStateController.isBothSplitAppsConfirmed() && !mSplitSelectStateController.isLaunchingFirstAppFullscreen()) { @@ -1352,6 +1353,15 @@ public class QuickstepLauncher extends Launcher { return (mTaskbarUIController != null && mTaskbarUIController.hasBubbles()); } + @Override + public boolean handleIncorrectSplitTargetSelection() { + if (enableSplitContextually() && !mSplitSelectStateController.isSplitSelectActive()) { + return false; + } + mSplitSelectStateController.getSplitInstructionsView().goBoing(); + return true; + } + private static final class LauncherTaskViewController extends TaskViewTouchController { diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java index c5317e3d5c..230a651698 100644 --- a/src/com/android/launcher3/views/ActivityContext.java +++ b/src/com/android/launcher3/views/ActivityContext.java @@ -154,6 +154,19 @@ public interface ActivityContext { return false; } + /** + * Handle user tapping on unsupported target when in split selection mode. + * See {@link #isSplitSelectionActive()} + * + * @return {@code true} if this method will handle the incorrect target selection, + * {@code false} if it could not be handled or if not possible to handle based on + * current split state + */ + default boolean handleIncorrectSplitTargetSelection() { + // Overridden + return false; + } + /** * The root view to support drag-and-drop and popup support. */ From 5e855d79129a902325d71ccfab57569ba2bd366f Mon Sep 17 00:00:00 2001 From: Shamali P Date: Fri, 2 Feb 2024 17:22:19 +0000 Subject: [PATCH 13/14] Fix the horizontal margins on the left panel in the two pane picker. The recycler view when displayed in single pane picker, for large screen gets a larger padding. But when displayed in two pane picker, it is not needed - so we override it. Foldable's unfolded portrait doesn't seem to have screenshot test - will look into if we can add one in follow up. Bug: 322719955 Test: Screenshot test for existing modes & manual (see bug) Flag: ACONFIG com.android.launcher3.enable_unfolded_two_pane_picker DEVELOPMENT Change-Id: Ibd72146e7e5230eec0d2ce01c3917819a73d8f32 --- res/values/dimens.xml | 2 ++ .../android/launcher3/widget/BaseWidgetSheet.java | 14 ++++++++++---- .../widget/picker/WidgetsTwoPaneSheet.java | 6 ++++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 3016559f96..34ee3ebe36 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -196,6 +196,8 @@ 20dp 2dp 16dp + + 0dp 24dp 0.5dp diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java index 9de7f62529..145ad8087e 100644 --- a/src/com/android/launcher3/widget/BaseWidgetSheet.java +++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java @@ -72,14 +72,21 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView public BaseWidgetSheet(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - mContentHorizontalMargin = getResources().getDimensionPixelSize( - R.dimen.widget_list_horizontal_margin); + mContentHorizontalMargin = getWidgetListHorizontalMargin(); mWidgetCellHorizontalPadding = getResources().getDimensionPixelSize( R.dimen.widget_cell_horizontal_padding); mNavBarScrimPaint = new Paint(); mNavBarScrimPaint.setColor(Themes.getNavBarScrimColor(mActivityContext)); } + /** + * Returns the margins to be applied to the left and right of the widget apps list. + */ + protected int getWidgetListHorizontalMargin() { + return getResources().getDimensionPixelSize( + R.dimen.widget_list_horizontal_margin); + } + protected int getScrimColor(Context context) { return context.getResources().getColor(R.color.widgets_picker_scrim); } @@ -142,8 +149,7 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView @Override public void setInsets(Rect insets) { mInsets.set(insets); - @Px int contentHorizontalMargin = getResources().getDimensionPixelSize( - R.dimen.widget_list_horizontal_margin); + @Px int contentHorizontalMargin = getWidgetListHorizontalMargin(); if (contentHorizontalMargin != mContentHorizontalMargin) { onContentHorizontalMarginChanged(contentHorizontalMargin); mContentHorizontalMargin = contentHorizontalMargin; diff --git a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java index 66562373d1..26c04f5116 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java +++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java @@ -302,6 +302,12 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { }; } + @Override + protected int getWidgetListHorizontalMargin() { + return getResources().getDimensionPixelSize( + R.dimen.widget_list_left_pane_horizontal_margin); + } + @Override protected boolean isTwoPane() { return true; From 94477b23e9b4f9dbd490d20109ab089c2aa08c22 Mon Sep 17 00:00:00 2001 From: Vadim Tryshev Date: Fri, 19 Jan 2024 12:04:45 -0800 Subject: [PATCH 14/14] Send finish callback even if there is no icon to animate to Fixes: 321297170 Test: TaplAllAppsIconsWorkingTest#testAppIconLaunchFromAllAppsFromHome Flag: none Change-Id: Ia6084dd14715bab36c7dd1c983fabedcf9b10630 --- .../src/com/android/quickstep/FallbackSwipeHandler.java | 2 +- src/com/android/launcher3/views/FloatingSurfaceView.java | 6 ++++-- .../launcher3/allapps/TaplAllAppsIconsWorkingTest.java | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java index e77a4504e5..b42eb067e4 100644 --- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java @@ -371,8 +371,8 @@ public class FallbackSwipeHandler extends if (mSpringAnim != null) { mSpringAnim.onTargetPositionChanged(); } - mOnFinishCallback = data.getParcelable(EXTRA_ON_FINISH_CALLBACK); } + mOnFinishCallback = data.getParcelable(EXTRA_ON_FINISH_CALLBACK); maybeSendEndMessage(); } catch (Exception e) { // Ignore diff --git a/src/com/android/launcher3/views/FloatingSurfaceView.java b/src/com/android/launcher3/views/FloatingSurfaceView.java index 76b6fdebad..c60e1a41cd 100644 --- a/src/com/android/launcher3/views/FloatingSurfaceView.java +++ b/src/com/android/launcher3/views/FloatingSurfaceView.java @@ -175,7 +175,6 @@ public class FloatingSurfaceView extends AbstractFloatingView implements if (!mTmpPosition.equals(mIconPosition)) { mIconPosition.set(mTmpPosition); - sendIconInfo(); LayoutParams lp = (LayoutParams) mSurfaceView.getLayoutParams(); lp.width = Math.round(mIconPosition.width()); @@ -184,6 +183,9 @@ public class FloatingSurfaceView extends AbstractFloatingView implements lp.topMargin = Math.round(mIconPosition.top); } } + + sendIconInfo(); + if (mIcon != null && iconChanged && !mIconBounds.isEmpty()) { // Record the icon display setCurrentIconVisible(true); @@ -197,7 +199,7 @@ public class FloatingSurfaceView extends AbstractFloatingView implements } private void sendIconInfo() { - if (mContract != null && !mIconPosition.isEmpty()) { + if (mContract != null) { mContract.sendEndPosition(mIconPosition, mLauncher, mSurfaceView.getSurfaceControl()); } } diff --git a/tests/src/com/android/launcher3/allapps/TaplAllAppsIconsWorkingTest.java b/tests/src/com/android/launcher3/allapps/TaplAllAppsIconsWorkingTest.java index 27a2c75795..ba74244bd0 100644 --- a/tests/src/com/android/launcher3/allapps/TaplAllAppsIconsWorkingTest.java +++ b/tests/src/com/android/launcher3/allapps/TaplAllAppsIconsWorkingTest.java @@ -62,5 +62,6 @@ public class TaplAllAppsIconsWorkingTest extends AbstractLauncherUiTest { } finally { allApps.unfreeze(); } + mLauncher.goHome(); } }