From a3f014d7372413a7f319913e04987db53fcc7fec Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 28 Apr 2022 19:43:46 -0700 Subject: [PATCH 1/9] Removing unused SearchSessionManager Bug: 220922858 Test: Presubmit Change-Id: I8264a2e9b978a850aa6ce69fcb698b0a3494c6c5 --- .../search/SearchSessionManager.java | 84 ------------------- 1 file changed, 84 deletions(-) delete mode 100644 quickstep/src/com/android/launcher3/search/SearchSessionManager.java diff --git a/quickstep/src/com/android/launcher3/search/SearchSessionManager.java b/quickstep/src/com/android/launcher3/search/SearchSessionManager.java deleted file mode 100644 index da85793225..0000000000 --- a/quickstep/src/com/android/launcher3/search/SearchSessionManager.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2022 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.search; - -import android.app.search.SearchSession; -import android.content.Context; - -import androidx.annotation.IntDef; -import androidx.annotation.UiThread; - -import com.android.launcher3.R; -import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.util.ResourceBasedOverride; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.List; - -/** Manages an all apps search session. */ -public class SearchSessionManager implements ResourceBasedOverride { - - /** Entry state for the search session (e.g. from all apps). */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(value = {ZERO_ALLAPPS, ZERO_QSB}) - public @interface ZeroEntryState {} - public static final int ZERO_ALLAPPS = 1; - public static final int ZERO_QSB = 2; - - /** Creates a {@link SearchSessionManager} instance. */ - public static SearchSessionManager newInstance(Context context) { - return Overrides.getObject( - SearchSessionManager.class, context, R.string.search_session_manager_class); - } - - /** The current {@link SearchSession}. */ - @UiThread - public void setSearchSession(SearchSession session) {} - - /** {@code true} if IME is shown. */ - public void setIsImeShown(boolean value) {} - - /** Returns {@code true} if IME is enabled. */ - public boolean getIsImeEnabled() { - return false; - } - - /** The current entry state for search. */ - public @ZeroEntryState int getEntryState() { - return ZERO_ALLAPPS; - } - - /** - * When user enters all apps surface via tap on home widget, set the state to - * {@code #ZERO_QSB}. When user exits, reset to {@code #ZERO_ALLAPPS} - */ - public void setEntryState(@ZeroEntryState int state) {} - - /** This will be called before opening all apps, to prepare zero state suggestions. */ - public void prepareZeroState() {} - - /** Apply predicted items for the search zero state. */ - public void setZeroStatePredictedItems(List items) {} - - /** Returns {@code true} if the session is valid and should be enabled. */ - public boolean isValidSession() { - return false; - } - - /** Called when the search session is destroyed. */ - public void onDestroy() {} -} From 0fd3b13d018cd66449349e6938d85d9cce6f9c2d Mon Sep 17 00:00:00 2001 From: Pat Manning Date: Tue, 26 Apr 2022 17:07:57 +0100 Subject: [PATCH 2/9] Finish recents animation on activity destroyed. Do not remove acitivity lifecycle callback on reset. Test: TaplTestsQuickstep.java testQuickSwitchFromApp Fix: 228137694 Change-Id: I454db1d029af479624999f2e5736aea1a8a97b87 --- quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index b90e8206f7..5acce899f9 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -163,7 +163,11 @@ public abstract class AbsSwipeUpHandler, if (mActivity != activity) { return; } + if (mTaskAnimationManager != null) { + mTaskAnimationManager.finishRunningRecentsAnimation(true); + } mRecentsView = null; + mActivity.unregisterActivityLifecycleCallbacks(mLifecycleCallbacks); mActivity = null; } }; @@ -1571,9 +1575,6 @@ public abstract class AbsSwipeUpHandler, private void reset() { mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED); - if (mActivity != null) { - mActivity.unregisterActivityLifecycleCallbacks(mLifecycleCallbacks); - } } /** From d08e03388faba87c1834b2efb234ba5070a55457 Mon Sep 17 00:00:00 2001 From: Pat Manning Date: Tue, 12 Apr 2022 11:12:57 +0000 Subject: [PATCH 3/9] Re-land "Animate overivew actions view hiding on scroll." Reverts commit f5f14acba3b0627f72237095c64798e9cbbb8608 Bug: 228137694 Bug: 221113300 Change-Id: I683092796f5de0476e09692897d80a3655ae6925 --- .../quickstep/views/OverviewActionsView.java | 4 +- .../android/quickstep/views/RecentsView.java | 48 +++++++++++++------ 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java index 49a540f0d1..1c4e497332 100644 --- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java +++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java @@ -56,7 +56,6 @@ public class OverviewActionsView extends FrameLayo HIDDEN_NON_ZERO_ROTATION, HIDDEN_NO_TASKS, HIDDEN_NO_RECENTS, - HIDDEN_FOCUSED_SCROLL, HIDDEN_SPLIT_SCREEN}) @Retention(RetentionPolicy.SOURCE) public @interface ActionsHiddenFlags { } @@ -64,8 +63,7 @@ public class OverviewActionsView extends FrameLayo public static final int HIDDEN_NON_ZERO_ROTATION = 1 << 0; public static final int HIDDEN_NO_TASKS = 1 << 1; public static final int HIDDEN_NO_RECENTS = 1 << 2; - public static final int HIDDEN_FOCUSED_SCROLL = 1 << 3; - public static final int HIDDEN_SPLIT_SCREEN = 1 << 4; + public static final int HIDDEN_SPLIT_SCREEN = 1 << 3; @IntDef(flag = true, value = { DISABLED_SCROLLING, diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 5d71ebd481..71b2cea444 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -378,6 +378,8 @@ public abstract class RecentsView 0) { @@ -1808,16 +1819,24 @@ public abstract class RecentsView Date: Tue, 26 Apr 2022 20:29:30 +0100 Subject: [PATCH 4/9] Fix hotseat width to span a number of columns Bug: 227344807 Test: manual Change-Id: Ice4e37929bcbb8c9cf3af340e67b6bec002578bd --- .../com/android/quickstep/TaskIconCache.java | 2 +- res/values/attrs.xml | 11 +++ res/xml/device_profiles.xml | 1 + src/com/android/launcher3/DeviceProfile.java | 72 +++++++++++++------ src/com/android/launcher3/Hotseat.java | 12 +--- .../launcher3/InvariantDeviceProfile.java | 23 +++++- .../launcher3/util/DisplayController.java | 6 +- .../launcher3/DeviceProfileBaseTest.kt | 3 + ...atSizeTest.kt => HotseatShownIconsTest.kt} | 4 +- .../com/android/launcher3/InlineQsbTest.kt | 16 ++--- .../models/DeviceEmulationData.java | 2 +- 11 files changed, 104 insertions(+), 48 deletions(-) rename tests/src/com/android/launcher3/{HotseatSizeTest.kt => HotseatShownIconsTest.kt} (97%) diff --git a/quickstep/src/com/android/quickstep/TaskIconCache.java b/quickstep/src/com/android/quickstep/TaskIconCache.java index 300f085b2a..3803f0350b 100644 --- a/quickstep/src/com/android/quickstep/TaskIconCache.java +++ b/quickstep/src/com/android/quickstep/TaskIconCache.java @@ -256,7 +256,7 @@ public class TaskIconCache implements DisplayInfoChangeListener { private BaseIconFactory getIconFactory() { if (mIconFactory == null) { mIconFactory = new BaseIconFactory(mContext, - DisplayController.INSTANCE.get(mContext).getInfo().densityDpi, + DisplayController.INSTANCE.get(mContext).getInfo().getDensityDpi(), mContext.getResources().getDimensionPixelSize(R.dimen.taskbar_icon_size)); } return mIconFactory; diff --git a/res/values/attrs.xml b/res/values/attrs.xml index dd3e08b19b..e85969bfc0 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -306,6 +306,17 @@ if not specified --> + + + + + + + + + + diff --git a/res/xml/device_profiles.xml b/res/xml/device_profiles.xml index 07ce59862b..258da80c40 100644 --- a/res/xml/device_profiles.xml +++ b/res/xml/device_profiles.xml @@ -176,6 +176,7 @@ launcher:allAppsBorderSpaceHorizontal="8" launcher:allAppsBorderSpaceVertical="16" launcher:allAppsBorderSpaceLandscape="16" + launcher:hotseatColumnSpanLandscape="4" launcher:hotseatBorderSpace="58" launcher:hotseatBorderSpaceLandscape="50.4" launcher:canBeDefault="true" /> diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 31f1da85c4..88030ae61f 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -158,6 +158,7 @@ public class DeviceProfile { public final int numShownHotseatIcons; public int hotseatCellHeightPx; private final int hotseatExtraVerticalSize; + private final boolean areNavButtonsInline; // In portrait: size = height, in landscape: size = width public int hotseatBarSizePx; public int hotseatBarTopPaddingPx; @@ -358,7 +359,7 @@ public class DeviceProfile { // We shrink hotseat sizes regardless of orientation, if nav buttons are inline and QSB // might be inline in either orientations, to keep hotseat size consistent across rotation. - boolean areNavButtonsInline = isTaskbarPresent && !isGestureMode; + areNavButtonsInline = isTaskbarPresent && !isGestureMode; if (areNavButtonsInline && canQsbInline) { numShownHotseatIcons = inv.numShrunkenHotseatIcons; } else { @@ -373,15 +374,14 @@ public class DeviceProfile { res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_top_padding); if (isQsbInline) { hotseatBarBottomPaddingPx = res.getDimensionPixelSize(R.dimen.inline_qsb_bottom_margin); - qsbWidth = calculateQsbWidth(); } else { hotseatBarBottomPaddingPx = (isTallDevice ? res.getDimensionPixelSize( R.dimen.dynamic_grid_hotseat_bottom_tall_padding) : res.getDimensionPixelSize( R.dimen.dynamic_grid_hotseat_bottom_non_tall_padding)) + res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_padding); - qsbWidth = 0; } + springLoadedHotseatBarTopMarginPx = res.getDimensionPixelSize( R.dimen.spring_loaded_hotseat_top_margin); hotseatBarSidePaddingEndPx = @@ -390,9 +390,7 @@ public class DeviceProfile { hotseatBarSidePaddingStartPx = isVerticalBarLayout() ? workspacePageIndicatorHeight : 0; hotseatExtraVerticalSize = res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_extra_vertical_size); - hotseatBorderSpace = pxFromDp(inv.hotseatBorderSpaces[mTypeIndex], mMetrics); - updateHotseatIconSize( - pxFromDp(inv.iconSize[INDEX_DEFAULT], mMetrics)); + updateHotseatIconSize(pxFromDp(inv.iconSize[INDEX_DEFAULT], mMetrics)); qsbBottomMarginOriginalPx = isScalableGrid ? res.getDimensionPixelSize(R.dimen.scalable_grid_qsb_bottom_margin) @@ -483,6 +481,10 @@ public class DeviceProfile { cellLayoutPadding); updateWorkspacePadding(); + // Hotseat and QSB width depends on updated cellSize and workspace padding + hotseatBorderSpace = calculateHotseatBorderSpace(); + qsbWidth = calculateQsbWidth(); + flingToDeleteThresholdVelocity = res.getDimensionPixelSize( R.dimen.drag_flingToDeleteMinVelocity); @@ -493,14 +495,26 @@ public class DeviceProfile { new DotRenderer(allAppsIconSizePx, dotPath, DEFAULT_DOT_SIZE); } + /** + * QSB width is always calculated because when in 3 button nav the width doesn't follow the + * width of the hotseat. + */ private int calculateQsbWidth() { - int columns = isTwoPanels ? inv.numColumns * 2 : inv.numColumns; + if (isQsbInline) { + int columns = isTwoPanels ? inv.numColumns * 2 : inv.numColumns; + return getIconToIconWidthForColumns(columns) + - iconSizePx * numShownHotseatIcons + - hotseatBorderSpace * numShownHotseatIcons; + } else { + int columns = inv.hotseatColumnSpan[mTypeIndex]; + return getIconToIconWidthForColumns(columns); + } + } - return cellWidthPx * columns - + cellLayoutBorderSpacePx.x * (columns - 1) - - (cellWidthPx - iconSizePx) // left and right cell space - - iconSizePx * numShownHotseatIcons - - hotseatBorderSpace * numShownHotseatIcons; + private int getIconToIconWidthForColumns(int columns) { + return columns * getCellSize().x + + (columns - 1) * cellLayoutBorderSpacePx.x + - (getCellSize().x - iconSizePx); // left and right cell space } private int getHorizontalMarginPx(InvariantDeviceProfile idp, Resources res) { @@ -741,13 +755,6 @@ public class DeviceProfile { // All apps updateAllAppsIconSize(scale, res); - // Hotseat - hotseatBorderSpace = pxFromDp(inv.hotseatBorderSpaces[mTypeIndex], mMetrics, scale); - if (isQsbInline) { - qsbWidth = calculateQsbWidth(); - } else { - qsbWidth = 0; - } updateHotseatIconSize(iconSizePx); // Folder icon @@ -755,6 +762,23 @@ public class DeviceProfile { folderIconOffsetYPx = (iconSizePx - folderIconSizePx) / 2; } + /** + * Hotseat width spans a certain number of columns on scalable grids. + * This method calculates the space between the icons to achieve that width. + */ + private int calculateHotseatBorderSpace() { + if (!isScalableGrid) return 0; + //TODO(http://b/228998082) remove this when 3 button spaces are fixed + if (areNavButtonsInline) { + return pxFromDp(inv.hotseatBorderSpaces[mTypeIndex], mMetrics); + } else { + int columns = inv.hotseatColumnSpan[mTypeIndex]; + float hotseatWidthPx = getIconToIconWidthForColumns(columns); + float hotseatIconsTotalPx = iconSizePx * numShownHotseatIcons; + return (int) (hotseatWidthPx - hotseatIconsTotalPx) / (numShownHotseatIcons - 1); + } + } + /** * Updates the iconSize for allApps* variants. @@ -1070,6 +1094,13 @@ public class DeviceProfile { mHotseatPadding.left -= diff; mHotseatPadding.right += diff; } + } else if (isScalableGrid) { + int sideSpacing = (availableWidthPx - qsbWidth) / 2; + mHotseatPadding.set(sideSpacing, + hotseatBarTopPaddingPx, + sideSpacing, + hotseatBarSizePx - hotseatCellHeightPx - hotseatBarTopPaddingPx + + mInsets.bottom); } else { // We want the edges of the hotseat to line up with the edges of the workspace, but the // icons in the hotseat are a different size, and so don't line up perfectly. To account @@ -1306,6 +1337,7 @@ public class DeviceProfile { writer.println(prefix + pxToDpStr("allAppsLeftRightMargin", allAppsLeftRightMargin)); writer.println(prefix + pxToDpStr("hotseatBarSizePx", hotseatBarSizePx)); + writer.println(prefix + "\tinv.hotseatColumnSpan: " + inv.hotseatColumnSpan[mTypeIndex]); writer.println(prefix + pxToDpStr("hotseatCellHeightPx", hotseatCellHeightPx)); writer.println(prefix + pxToDpStr("hotseatBarTopPaddingPx", hotseatBarTopPaddingPx)); writer.println(prefix + pxToDpStr("hotseatBarBottomPaddingPx", hotseatBarBottomPaddingPx)); @@ -1384,7 +1416,7 @@ public class DeviceProfile { private static Context getContext(Context c, Info info, int orientation, WindowBounds bounds) { Configuration config = new Configuration(c.getResources().getConfiguration()); config.orientation = orientation; - config.densityDpi = info.densityDpi; + config.densityDpi = info.getDensityDpi(); config.smallestScreenWidthDp = (int) info.smallestSizeDp(bounds); return c.createConfigurationContext(config); } diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index a9db5ce089..76106fc58d 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -173,17 +173,9 @@ public class Hotseat extends CellLayout implements Insettable { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); - int width; - if (mActivity.getDeviceProfile().isQsbInline) { - width = mActivity.getDeviceProfile().qsbWidth; - } else { - MarginLayoutParams qsbParams = (MarginLayoutParams) mQsb.getLayoutParams(); - width = getShortcutsAndWidgets().getMeasuredWidth() - - qsbParams.getMarginStart() - - qsbParams.getMarginEnd(); - } + int qsbWidth = mActivity.getDeviceProfile().qsbWidth; - mQsb.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), + mQsb.measure(MeasureSpec.makeMeasureSpec(qsbWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(mQsbHeight, MeasureSpec.EXACTLY)); } diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java index 36c179798f..89b177165f 100644 --- a/src/com/android/launcher3/InvariantDeviceProfile.java +++ b/src/com/android/launcher3/InvariantDeviceProfile.java @@ -125,6 +125,7 @@ public class InvariantDeviceProfile { public PointF[] borderSpaces; public float folderBorderSpace; public float[] hotseatBorderSpaces; + public int[] hotseatColumnSpan; public float[] horizontalMargin; @@ -356,6 +357,7 @@ public class InvariantDeviceProfile { numDatabaseHotseatIcons = deviceType == TYPE_MULTI_DISPLAY ? closestProfile.numDatabaseHotseatIcons : closestProfile.numHotseatIcons; hotseatBorderSpaces = displayOption.hotseatBorderSpaces; + hotseatColumnSpan = displayOption.hotseatColumnSpan; numAllAppsColumns = closestProfile.numAllAppsColumns; numDatabaseAllAppsColumns = deviceType == TYPE_MULTI_DISPLAY @@ -396,7 +398,8 @@ public class InvariantDeviceProfile { // We need to ensure that there is enough extra space in the wallpaper // for the intended parallax effects float parallaxFactor = - dpiFromPx(Math.min(displayWidth, displayHeight), displayInfo.densityDpi) < 720 + dpiFromPx(Math.min(displayWidth, displayHeight), displayInfo.getDensityDpi()) + < 720 ? 2 : wallpaperTravelToScreenWidthRatio(displayWidth, displayHeight); defaultWallpaperSize.x = @@ -585,8 +588,8 @@ public class InvariantDeviceProfile { } } - float width = dpiFromPx(minWidthPx, displayInfo.densityDpi); - float height = dpiFromPx(minHeightPx, displayInfo.densityDpi); + float width = dpiFromPx(minWidthPx, displayInfo.getDensityDpi()); + float height = dpiFromPx(minHeightPx, displayInfo.getDensityDpi()); // Sort the profiles based on the closeness to the device size Collections.sort(points, (a, b) -> @@ -806,7 +809,9 @@ public class InvariantDeviceProfile { private float folderBorderSpace; private final PointF[] borderSpaces = new PointF[COUNT_SIZES]; private final float[] horizontalMargin = new float[COUNT_SIZES]; + //TODO(http://b/228998082) remove this when 3 button spaces are fixed private final float[] hotseatBorderSpaces = new float[COUNT_SIZES]; + private final int[] hotseatColumnSpan = new int[COUNT_SIZES]; private final float[] iconSizes = new float[COUNT_SIZES]; private final float[] textSizes = new float[COUNT_SIZES]; @@ -1032,6 +1037,17 @@ public class InvariantDeviceProfile { R.styleable.ProfileDisplayOption_hotseatBorderSpaceTwoPanelPortrait, hotseatBorderSpaces[INDEX_DEFAULT]); + hotseatColumnSpan[INDEX_DEFAULT] = a.getInt( + R.styleable.ProfileDisplayOption_hotseatColumnSpan, grid.numColumns); + hotseatColumnSpan[INDEX_LANDSCAPE] = a.getInt( + R.styleable.ProfileDisplayOption_hotseatColumnSpanLandscape, grid.numColumns); + hotseatColumnSpan[INDEX_TWO_PANEL_LANDSCAPE] = a.getInt( + R.styleable.ProfileDisplayOption_hotseatColumnSpanTwoPanelLandscape, + grid.numColumns); + hotseatColumnSpan[INDEX_TWO_PANEL_PORTRAIT] = a.getInt( + R.styleable.ProfileDisplayOption_hotseatColumnSpanTwoPanelPortrait, + grid.numColumns); + a.recycle(); } @@ -1090,6 +1106,7 @@ public class InvariantDeviceProfile { minCellSize[i].y += p.minCellSize[i].y; horizontalMargin[i] += p.horizontalMargin[i]; hotseatBorderSpaces[i] += p.hotseatBorderSpaces[i]; + hotseatColumnSpan[i] = p.hotseatColumnSpan[i]; allAppsCellSize[i].x += p.allAppsCellSize[i].x; allAppsCellSize[i].y += p.allAppsCellSize[i].y; allAppsIconSizes[i] += p.allAppsIconSizes[i]; diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java index 777da23e86..7c73be51c6 100644 --- a/src/com/android/launcher3/util/DisplayController.java +++ b/src/com/android/launcher3/util/DisplayController.java @@ -290,7 +290,7 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { // Configuration property public final float fontScale; - public final int densityDpi; + private final int densityDpi; public final NavigationMode navigationMode; private final PortraitSize mScreenSizeDp; @@ -357,6 +357,10 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { public float smallestSizeDp(WindowBounds bounds) { return dpiFromPx(Math.min(bounds.bounds.width(), bounds.bounds.height()), densityDpi); } + + public int getDensityDpi() { + return densityDpi; + } } /** diff --git a/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt b/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt index f91f1c4288..6d0fcb6faa 100644 --- a/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt +++ b/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt @@ -64,6 +64,7 @@ abstract class DeviceProfileBaseTest { windowBounds = WindowBounds(x, y, x, y - 100, 0) whenever(info.isTablet(any())).thenReturn(false) + whenever(info.getDensityDpi()).thenReturn(560) inv = newScalableInvariantDeviceProfile() } @@ -77,6 +78,7 @@ abstract class DeviceProfileBaseTest { windowBounds = WindowBounds(x, y, x, y - 100, 0) whenever(info.isTablet(any())).thenReturn(true) + whenever(info.getDensityDpi()).thenReturn(320) inv = newScalableInvariantDeviceProfile() } @@ -107,6 +109,7 @@ abstract class DeviceProfileBaseTest { PointF(16f, 16f) ).toTypedArray() hotseatBorderSpaces = FloatArray(4) { 16f } + hotseatColumnSpan = IntArray(4) { 4 } iconSize = FloatArray(4) { 56f } allAppsIconSize = FloatArray(4) { 56f } iconTextSize = FloatArray(4) { 14f } diff --git a/tests/src/com/android/launcher3/HotseatSizeTest.kt b/tests/src/com/android/launcher3/HotseatShownIconsTest.kt similarity index 97% rename from tests/src/com/android/launcher3/HotseatSizeTest.kt rename to tests/src/com/android/launcher3/HotseatShownIconsTest.kt index a44939f4cf..593239d6f7 100644 --- a/tests/src/com/android/launcher3/HotseatSizeTest.kt +++ b/tests/src/com/android/launcher3/HotseatShownIconsTest.kt @@ -23,15 +23,13 @@ import com.android.launcher3.InvariantDeviceProfile.TYPE_TABLET import com.google.common.truth.Truth.assertThat import org.junit.Test import org.junit.runner.RunWith -import org.mockito.ArgumentMatchers -import org.mockito.Mockito.`when` as whenever /** * Test for [DeviceProfile] */ @SmallTest @RunWith(AndroidJUnit4::class) -class HotseatSizeTest : DeviceProfileBaseTest() { +class HotseatShownIconsTest : DeviceProfileBaseTest() { @Test fun hotseat_size_is_normal_for_handhelds() { diff --git a/tests/src/com/android/launcher3/InlineQsbTest.kt b/tests/src/com/android/launcher3/InlineQsbTest.kt index e00dca86e2..905c1e1a0f 100644 --- a/tests/src/com/android/launcher3/InlineQsbTest.kt +++ b/tests/src/com/android/launcher3/InlineQsbTest.kt @@ -29,17 +29,16 @@ import org.junit.runner.RunWith class InlineQsbTest : DeviceProfileBaseTest() { @Test - fun qsbWidth_is_match_parent_for_phones() { + fun qsb_is_not_inline_for_phones() { initializeVarsForPhone() val dp = newDP() assertThat(dp.isQsbInline).isFalse() - assertThat(dp.qsbWidth).isEqualTo(0) } @Test - fun qsbWidth_is_match_parent_for_tablet_portrait() { + fun qsb_is_inline_for_tablet_portrait() { initializeVarsForTablet() inv = newScalableInvariantDeviceProfile().apply { inlineQsb = booleanArrayOf( @@ -62,11 +61,10 @@ class InlineQsbTest : DeviceProfileBaseTest() { ) assertThat(dp.isQsbInline).isFalse() - assertThat(dp.qsbWidth).isEqualTo(0) } @Test - fun qsbWidth_has_size_for_tablet_landscape() { + fun qsb_is_inline_for_tablet_landscape() { initializeVarsForTablet(isLandscape = true) inv = newScalableInvariantDeviceProfile().apply { inlineQsb = booleanArrayOf( @@ -75,16 +73,17 @@ class InlineQsbTest : DeviceProfileBaseTest() { false, false ) + numColumns = 6 + numRows = 5 + numShownHotseatIcons = 6 } val dp = newDP() if (dp.hotseatQsbHeight > 0) { assertThat(dp.isQsbInline).isTrue() - assertThat(dp.qsbWidth).isGreaterThan(0) } else { // Launcher3 doesn't have QSB height assertThat(dp.isQsbInline).isFalse() - assertThat(dp.qsbWidth).isEqualTo(0) } } @@ -92,14 +91,13 @@ class InlineQsbTest : DeviceProfileBaseTest() { * This test is to make sure that a tablet doesn't inline the QSB if the layout doesn't support */ @Test - fun qsbWidth_is_match_parent_for_tablet_landscape_without_inline() { + fun qsb_is_not_inline_for_tablet_landscape_without_inline() { initializeVarsForTablet(isLandscape = true) useTwoPanels = true val dp = newDP() assertThat(dp.isQsbInline).isFalse() - assertThat(dp.qsbWidth).isEqualTo(0) } } \ No newline at end of file diff --git a/tests/src/com/android/launcher3/deviceemulator/models/DeviceEmulationData.java b/tests/src/com/android/launcher3/deviceemulator/models/DeviceEmulationData.java index 36235134f5..8d275cc04b 100644 --- a/tests/src/com/android/launcher3/deviceemulator/models/DeviceEmulationData.java +++ b/tests/src/com/android/launcher3/deviceemulator/models/DeviceEmulationData.java @@ -135,7 +135,7 @@ public class DeviceEmulationData { resourceOverrides.put(s, getDimenByName(s, context.getResources(), 0)); } return new DeviceEmulationData(info.currentSize.x, info.currentSize.y, - info.densityDpi, info.cutout, code, grids, resourceOverrides); + info.getDensityDpi(), info.cutout, code, grids, resourceOverrides); } public static DeviceEmulationData getDevice(String deviceCode) throws Exception { From 3091f0a4feb0f3d03c6455b28793e25a011af5d0 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 29 Apr 2022 09:49:35 -0700 Subject: [PATCH 5/9] Removing ununsed append logic in search Bug: 229860311 Test: Manual Change-Id: Id6a72784b186fc5f0aaeac52f2a66fa35711fe4c --- .../allapps/AlphabeticalAppsList.java | 33 ++++++------------- .../search/AppsSearchContainerLayout.java | 8 ----- .../launcher3/search/SearchCallback.java | 7 ---- .../search/WidgetsSearchBarController.java | 5 --- 4 files changed, 10 insertions(+), 43 deletions(-) diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java index 9f0c1cca65..2a16210861 100644 --- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java +++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java @@ -192,27 +192,6 @@ public class AlphabeticalAppsList implement return true; } - public boolean appendSearchResults(ArrayList results) { - if (hasFilter() && results != null && results.size() > 0) { - updateSearchAdapterItems(results, mSearchResults.size()); - refreshRecyclerView(); - return true; - } - return false; - } - - void updateSearchAdapterItems(ArrayList list, int offset) { - for (int i = 0; i < list.size(); i++) { - AdapterItem adapterItem = list.get(i); - adapterItem.position = offset + i; - mAdapterItems.add(adapterItem); - - if (adapterItem.isCountedForAccessibility()) { - mAccessibilityResultsCount++; - } - } - } - /** * Updates internals when the set of apps are updated. */ @@ -282,7 +261,6 @@ public class AlphabeticalAppsList implement String lastSectionName = null; FastScrollSectionInfo lastFastScrollerSectionInfo = null; int position = 0; - int appIndex = 0; // Prepare to update the list of sections, filtered apps, etc. mAccessibilityResultsCount = 0; @@ -319,7 +297,16 @@ public class AlphabeticalAppsList implement mAdapterItems.add(appItem); } } else { - updateSearchAdapterItems(mSearchResults, 0); + int count = mSearchResults.size(); + for (int i = 0; i < count; i++) { + AdapterItem adapterItem = mSearchResults.get(i); + adapterItem.position = i; + mAdapterItems.add(adapterItem); + + if (adapterItem.isCountedForAccessibility()) { + mAccessibilityResultsCount++; + } + } if (!FeatureFlags.ENABLE_DEVICE_SEARCH.get()) { // Append the search market item if (hasNoFilteredResults()) { diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java index 893e547340..bc2c318ecb 100644 --- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java +++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java @@ -176,14 +176,6 @@ public class AppsSearchContainerLayout extends ExtendedEditText } } - @Override - public void onAppendSearchResult(String query, ArrayList items) { - if (items != null) { - mApps.appendSearchResults(items); - notifyResultChanged(); - } - } - @Override public void clearSearchResult() { if (mApps.setSearchResults(null)) { diff --git a/src/com/android/launcher3/search/SearchCallback.java b/src/com/android/launcher3/search/SearchCallback.java index 5796116963..495a303a7e 100644 --- a/src/com/android/launcher3/search/SearchCallback.java +++ b/src/com/android/launcher3/search/SearchCallback.java @@ -31,13 +31,6 @@ public interface SearchCallback { */ void onSearchResult(String query, ArrayList items); - /** - * Called when the search from secondary source is complete. - * - * @param items list of search results - */ - void onAppendSearchResult(String query, ArrayList items); - /** * Called when the search results should be cleared. */ diff --git a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java index 2751a52796..a15508a617 100644 --- a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java +++ b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java @@ -94,11 +94,6 @@ public class WidgetsSearchBarController implements TextWatcher, mSearchModeListener.onSearchResults(items); } - @Override - public void onAppendSearchResult(String query, ArrayList items) { - // Not needed. - } - @Override public void clearSearchResult() { // Any existing search session will be cancelled by setting text to empty. From f2cd2f7748b37900f20ae083c7628e232b2debc3 Mon Sep 17 00:00:00 2001 From: Zak Cohen Date: Thu, 28 Apr 2022 17:50:16 -0700 Subject: [PATCH 6/9] Update TaskOverlay corner radius as fullscreen parameters are updated. Bug: 230470826 Test: Build and run Change-Id: I3b6914bf7423ec60d28d2d06ee5225de1b6862c1 --- quickstep/src/com/android/quickstep/TaskOverlayFactory.java | 4 ++++ .../src/com/android/quickstep/views/TaskThumbnailView.java | 1 + quickstep/src/com/android/quickstep/views/TaskView.java | 3 +-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java index 2d1f17c924..4a3e92aa71 100644 --- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java +++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java @@ -316,6 +316,10 @@ public class TaskOverlayFactory implements ResourceBasedOverride { Toast.LENGTH_LONG).show(); } + /** Called when the snapshot has updated its full screen drawing parameters. */ + public void setFullscreenParams(TaskView.FullscreenDrawParams fullscreenParams) { + } + private class ScreenshotSystemShortcut extends SystemShortcut { private final BaseDraggingActivity mActivity; diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java index bff86512f9..d8120ff255 100644 --- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java +++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java @@ -283,6 +283,7 @@ public class TaskThumbnailView extends View { public void setFullscreenParams(TaskView.FullscreenDrawParams fullscreenParams) { mFullscreenParams = fullscreenParams; + getTaskOverlay().setFullscreenParams(fullscreenParams); invalidate(); } diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index 9c5c643f29..e433615d70 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -20,7 +20,6 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.widget.Toast.LENGTH_SHORT; import static com.android.launcher3.AbstractFloatingView.TYPE_TASK_MENU; -import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT; import static com.android.launcher3.Utilities.comp; import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor; import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL; @@ -1026,7 +1025,7 @@ public class TaskView extends FrameLayout implements Reusable { } public float getTaskCornerRadius() { - return TaskCornerRadius.get(mActivity); + return mCurrentFullscreenParams.mCornerRadius; } @Override From 8e0e88bb2fafedd2d7a5e843e00755f045974552 Mon Sep 17 00:00:00 2001 From: Schneider Victor-tulias Date: Fri, 29 Apr 2022 15:32:37 -0700 Subject: [PATCH 7/9] Update home, back and overview gesture tutorial introductions to be clearer for blind users Added A11Y strings for the home, back and overview gesture tutorial step introductions. These strings give clearer instructions that work with talkback. Fixes: 202492454 Test: manual Change-Id: I1eefd6ecf3e3c576a7c1cf6dbf7b824e5be13860 --- quickstep/res/values/strings.xml | 6 +++ .../BackGestureTutorialController.java | 11 +++-- .../HomeGestureTutorialController.java | 11 +++-- .../OverviewGestureTutorialController.java | 11 +++-- .../interaction/TutorialController.java | 45 +++++++++++++------ .../interaction/TutorialFragment.java | 32 ++++++++++--- 6 files changed, 88 insertions(+), 28 deletions(-) diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml index f80deeba45..81b0dd297c 100644 --- a/quickstep/res/values/strings.xml +++ b/quickstep/res/values/strings.xml @@ -109,6 +109,8 @@ Swipe to go back To go back to the last screen, swipe from the left or right edge to the middle of the screen. + + To go back to the last screen, swipe with 2 fingers from the left or right edge to the middle of the screen. Make sure you swipe up from the bottom edge of the screen. @@ -123,6 +125,8 @@ Swipe to go home Swipe up from the bottom of your screen. This gesture always takes you to the Home screen. + + Swipe up with 2 fingers from the bottom of the screen. This gesture always takes you to the Home screen. Make sure you swipe up from the bottom edge of the screen. @@ -138,6 +142,8 @@ Swipe to switch apps To switch between apps, swipe up from the bottom of your screen, hold, then release. + + To switch between apps, swipe up with 2 fingers from the bottom of your screen, hold, then release. Tutorial: Assistant diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java index 9ba55778d1..35d9f22d3a 100644 --- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java @@ -33,17 +33,22 @@ final class BackGestureTutorialController extends TutorialController { } @Override - public Integer getIntroductionTitle() { + public int getIntroductionTitle() { return R.string.back_gesture_intro_title; } @Override - public Integer getIntroductionSubtitle() { + public int getIntroductionSubtitle() { return R.string.back_gesture_intro_subtitle; } @Override - public Integer getSuccessFeedbackSubtitle() { + public int getSpokenIntroductionSubtitle() { + return R.string.back_gesture_spoken_intro_subtitle; + } + + @Override + public int getSuccessFeedbackSubtitle() { return mTutorialFragment.isAtFinalStep() ? R.string.back_gesture_feedback_complete_without_follow_up : R.string.back_gesture_feedback_complete_with_overview_follow_up; diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java index 6254313f74..f519d50613 100644 --- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java @@ -32,17 +32,22 @@ final class HomeGestureTutorialController extends SwipeUpGestureTutorialControll } @Override - public Integer getIntroductionTitle() { + public int getIntroductionTitle() { return R.string.home_gesture_intro_title; } @Override - public Integer getIntroductionSubtitle() { + public int getIntroductionSubtitle() { return R.string.home_gesture_intro_subtitle; } @Override - public Integer getSuccessFeedbackSubtitle() { + public int getSpokenIntroductionSubtitle() { + return R.string.home_gesture_spoken_intro_subtitle; + } + + @Override + public int getSuccessFeedbackSubtitle() { return mTutorialFragment.isAtFinalStep() ? R.string.home_gesture_feedback_complete_without_follow_up : R.string.home_gesture_feedback_complete_with_follow_up; diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java index 09640c675b..6b016cee13 100644 --- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java @@ -42,17 +42,22 @@ final class OverviewGestureTutorialController extends SwipeUpGestureTutorialCont } @Override - public Integer getIntroductionTitle() { + public int getIntroductionTitle() { return R.string.overview_gesture_intro_title; } @Override - public Integer getIntroductionSubtitle() { + public int getIntroductionSubtitle() { return R.string.overview_gesture_intro_subtitle; } @Override - public Integer getSuccessFeedbackSubtitle() { + public int getSpokenIntroductionSubtitle() { + return R.string.overview_gesture_spoken_intro_subtitle; + } + + @Override + public int getSuccessFeedbackSubtitle() { return mTutorialFragment.getNumSteps() > 1 && mTutorialFragment.isAtFinalStep() ? R.string.overview_gesture_feedback_complete_with_follow_up : R.string.overview_gesture_feedback_complete_without_follow_up; diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java index 6a8894e88f..fa7d848a7c 100644 --- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java @@ -62,7 +62,7 @@ import java.util.ArrayList; abstract class TutorialController implements BackGestureAttemptCallback, NavBarGestureAttemptCallback { - private static final String TAG = "TutorialController"; + private static final String LOG_TAG = "TutorialController"; private static final float FINGER_DOT_VISIBLE_ALPHA = 0.7f; private static final float FINGER_DOT_SMALL_SCALE = 0.7f; @@ -217,18 +217,23 @@ abstract class TutorialController implements BackGestureAttemptCallback, } @StringRes - public Integer getIntroductionTitle() { - return null; + public int getIntroductionTitle() { + return NO_ID; } @StringRes - public Integer getIntroductionSubtitle() { - return null; + public int getIntroductionSubtitle() { + return NO_ID; } @StringRes - public Integer getSuccessFeedbackSubtitle() { - return null; + public int getSpokenIntroductionSubtitle() { + return NO_ID; + } + + @StringRes + public int getSuccessFeedbackSubtitle() { + return NO_ID; } void showFeedback() { @@ -247,7 +252,16 @@ abstract class TutorialController implements BackGestureAttemptCallback, * Show feedback reflecting a successful gesture attempt. **/ void showSuccessFeedback() { - showFeedback(getSuccessFeedbackSubtitle(), true); + int successSubtitleResId = getSuccessFeedbackSubtitle(); + if (successSubtitleResId == NO_ID) { + // Allow crash since this should never be reached with a tutorial controller used in + // production. + Log.e(LOG_TAG, + "Cannot show success feedback for tutorial step: " + mTutorialType + + ", no success feedback subtitle", + new IllegalStateException()); + } + showFeedback(successSubtitleResId, true); } /** @@ -269,6 +283,7 @@ abstract class TutorialController implements BackGestureAttemptCallback, isGestureSuccessful ? R.string.gesture_tutorial_nice : R.string.gesture_tutorial_try_again, subtitleResId, + NO_ID, isGestureSuccessful, false); } @@ -276,6 +291,7 @@ abstract class TutorialController implements BackGestureAttemptCallback, void showFeedback( int titleResId, int subtitleResId, + int spokenSubtitleResId, boolean isGestureSuccessful, boolean useGestureAnimationDelay) { mFeedbackTitleView.removeCallbacks(mTitleViewCallback); @@ -287,7 +303,10 @@ abstract class TutorialController implements BackGestureAttemptCallback, mFeedbackTitleView.setText(titleResId); TextView subtitle = mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_feedback_subtitle); - subtitle.setText(subtitleResId); + subtitle.setText(spokenSubtitleResId == NO_ID + ? mContext.getText(subtitleResId) + : Utilities.wrapForTts( + mContext.getText(subtitleResId), mContext.getString(spokenSubtitleResId))); if (isGestureSuccessful) { if (mTutorialFragment.isAtFinalStep()) { showActionButton(); @@ -580,7 +599,7 @@ abstract class TutorialController implements BackGestureAttemptCallback, packageManager.getApplicationInfo( PIXEL_TIPS_APP_PACKAGE_NAME, PackageManager.GET_META_DATA)); } catch (PackageManager.NameNotFoundException e) { - Log.e(TAG, + Log.e(LOG_TAG, "Could not find app label for package name: " + PIXEL_TIPS_APP_PACKAGE_NAME + ". Defaulting to 'Pixel Tips.'", @@ -593,7 +612,7 @@ abstract class TutorialController implements BackGestureAttemptCallback, subtitleTextView.setText( mContext.getString(R.string.skip_tutorial_dialog_subtitle, tipsAppName)); } else { - Log.w(TAG, "No subtitle view in the skip tutorial dialog to update."); + Log.w(LOG_TAG, "No subtitle view in the skip tutorial dialog to update."); } Button cancelButton = (Button) contentView.findViewById( @@ -602,7 +621,7 @@ abstract class TutorialController implements BackGestureAttemptCallback, cancelButton.setOnClickListener( v -> tutorialDialog.dismiss()); } else { - Log.w(TAG, "No cancel button in the skip tutorial dialog to update."); + Log.w(LOG_TAG, "No cancel button in the skip tutorial dialog to update."); } Button confirmButton = contentView.findViewById( @@ -613,7 +632,7 @@ abstract class TutorialController implements BackGestureAttemptCallback, tutorialDialog.dismiss(); }); } else { - Log.w(TAG, "No confirm button in the skip tutorial dialog to update."); + Log.w(LOG_TAG, "No confirm button in the skip tutorial dialog to update."); } tutorialDialog.getWindow().setBackgroundDrawable( diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java index 33e800d1c0..1599c8c32d 100644 --- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java +++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java @@ -15,6 +15,8 @@ */ package com.android.quickstep.interaction; +import static android.view.View.NO_ID; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.app.Activity; @@ -211,13 +213,31 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener { if (isGestureComplete()) { mTutorialController.showSuccessFeedback(); } else if (!mIntroductionShown) { - Integer introTileStringResId = mTutorialController.getIntroductionTitle(); - Integer introSubtitleResId = mTutorialController.getIntroductionSubtitle(); - if (introTileStringResId != null && introSubtitleResId != null) { - mTutorialController.showFeedback( - introTileStringResId, introSubtitleResId, false, true); - mIntroductionShown = true; + int introTitleResId = mTutorialController.getIntroductionTitle(); + int introSubtitleResId = mTutorialController.getIntroductionSubtitle(); + if (introTitleResId == NO_ID) { + // Allow crash since this should never be reached with a tutorial controller used in + // production. + Log.e(LOG_TAG, + "Cannot show introduction feedback for tutorial step: " + mTutorialType + + ", no introduction feedback title", + new IllegalStateException()); } + if (introTitleResId == NO_ID) { + // Allow crash since this should never be reached with a tutorial controller used in + // production. + Log.e(LOG_TAG, + "Cannot show introduction feedback for tutorial step: " + mTutorialType + + ", no introduction feedback subtitle", + new IllegalStateException()); + } + mTutorialController.showFeedback( + introTitleResId, + introSubtitleResId, + mTutorialController.getSpokenIntroductionSubtitle(), + false, + true); + mIntroductionShown = true; } } From f6254c594763aa092d041a387a7d2ea9288abb27 Mon Sep 17 00:00:00 2001 From: Anushree Ganjam Date: Fri, 29 Apr 2022 00:46:22 +0000 Subject: [PATCH 8/9] Do not add HOTSEAT_ICONS to visible elements for device type "phone" in ALL_APPS State HOTSEAT_ICONS got added to visible elements for ALL_APPS State in ag/16992837. ============================================================ Phone Before: HotSeat present in view hierarchy - https://hsv.googleplex.com/4906040983289856?node=41 Video: https://b.corp.google.com/issues/228803923#comment9 After: HotSeat not present in view hierarchy - https://hsv.googleplex.com/5379653922455552?node=42 Video: https://b.corp.google.com/issues/228803923#comment11 ============================================================ Tablets I couldn't test this implementation on tablet. But I have verified on a phone locally by adding HOTSEAT_ICONS to visible elements and then verifying "IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS" get set and hotseat icons are not focusable in all apps. Video : https://b.corp.google.com/issues/228803923#comment14 ============================================================ Bug: 228803923 Bug: 227565451 Test: Manual. See the video attached in bug. Change-Id: I055e3bb61c8cfd240e0fe1000fe3a391a150f6d1 --- .../android/launcher3/uioverrides/states/AllAppsState.java | 7 +++++-- src/com/android/launcher3/LauncherState.java | 3 +++ .../launcher3/WorkspaceStateTransitionAnimation.java | 7 +++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java index cd14b3f75c..3c5f216772 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java @@ -30,7 +30,8 @@ import com.android.launcher3.util.Themes; */ public class AllAppsState extends LauncherState { - private static final int STATE_FLAGS = FLAG_WORKSPACE_INACCESSIBLE | FLAG_CLOSE_POPUPS; + private static final int STATE_FLAGS = + FLAG_WORKSPACE_INACCESSIBLE | FLAG_CLOSE_POPUPS | FLAG_HOTSEAT_INACCESSIBLE; public AllAppsState(int id) { super(id, LAUNCHER_STATE_ALLAPPS, STATE_FLAGS); @@ -88,7 +89,9 @@ public class AllAppsState extends LauncherState { @Override public int getVisibleElements(Launcher launcher) { - return ALL_APPS_CONTENT | HOTSEAT_ICONS; + // Don't add HOTSEAT_ICONS for phones in ALL_APPS state. + return launcher.getDeviceProfile().isPhone ? ALL_APPS_CONTENT + : ALL_APPS_CONTENT | HOTSEAT_ICONS; } @Override diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java index baee49f6b7..c0bcaa39df 100644 --- a/src/com/android/launcher3/LauncherState.java +++ b/src/com/android/launcher3/LauncherState.java @@ -80,6 +80,9 @@ public abstract class LauncherState implements BaseState { public static final int FLAG_CLOSE_POPUPS = BaseState.getFlag(6); public static final int FLAG_OVERVIEW_UI = BaseState.getFlag(7); + // Flag indicating that hotseat and its contents are not accessible. + public static final int FLAG_HOTSEAT_INACCESSIBLE = BaseState.getFlag(8); + public static final float NO_OFFSET = 0; public static final float NO_SCALE = 1; diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java index 84b95ec188..bf56ac0443 100644 --- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java +++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java @@ -25,6 +25,7 @@ import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X; import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y; import static com.android.launcher3.LauncherAnimUtils.WORKSPACE_SCALE_PROPERTY_FACTORY; import static com.android.launcher3.LauncherState.FLAG_HAS_SYS_UI_SCRIM; +import static com.android.launcher3.LauncherState.FLAG_HOTSEAT_INACCESSIBLE; import static com.android.launcher3.LauncherState.HINT_STATE; import static com.android.launcher3.LauncherState.HOTSEAT_ICONS; import static com.android.launcher3.LauncherState.NORMAL; @@ -151,6 +152,12 @@ public class WorkspaceStateTransitionAnimation { propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(), workspacePageIndicatorAlpha, fadeInterpolator); + // Update the accessibility flags for hotseat based on launcher state. + hotseat.setImportantForAccessibility( + state.hasFlag(FLAG_HOTSEAT_INACCESSIBLE) + ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS + : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); + Interpolator translationInterpolator = config.getInterpolator(ANIM_WORKSPACE_TRANSLATE, ZOOM_OUT); propertySetter.setFloat(mWorkspace, VIEW_TRANSLATE_X, From 883e7e412b1e95d430dafdfb17c38172deeec4d8 Mon Sep 17 00:00:00 2001 From: Shan Huang Date: Fri, 8 Apr 2022 00:52:44 +0000 Subject: [PATCH 9/9] Provide the back callback instance when unregistering it from SysUI. Bug: 228535747 Test: atest BackAnimationControllerTest Test: Make sure back to home animation works on tablets and phones. Change-Id: Iacbd581f382da50e96cfefbefe569800e9e1043b --- .../LauncherBackAnimationController.java | 58 ++++++++++--------- .../com/android/quickstep/SystemUiProxy.java | 10 +++- 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java index 921674a2d4..4d854b6716 100644 --- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java +++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java @@ -46,6 +46,7 @@ import com.android.quickstep.util.RectFSpringAnim; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat; + /** * Controls the animation of swiping back and returning to launcher. * @@ -88,6 +89,7 @@ public class LauncherBackAnimationController { private boolean mAnimatorSetInProgress = false; private float mBackProgress = 0; private boolean mBackInProgress = false; + private IOnBackInvokedCallback mBackCallback; public LauncherBackAnimationController( BaseQuickstepLauncher launcher, @@ -113,34 +115,35 @@ public class LauncherBackAnimationController { * @param handler Handler to the thread to run the animations on. */ public void registerBackCallbacks(Handler handler) { - SystemUiProxy.INSTANCE.get(mLauncher).setBackToLauncherCallback( - new IOnBackInvokedCallback.Stub() { - @Override - public void onBackCancelled() { - handler.post(() -> resetPositionAnimated()); - } + mBackCallback = new IOnBackInvokedCallback.Stub() { + @Override + public void onBackCancelled() { + handler.post(() -> resetPositionAnimated()); + } - @Override - public void onBackInvoked() { - handler.post(() -> startTransition()); - } + @Override + public void onBackInvoked() { + handler.post(() -> startTransition()); + } - @Override - public void onBackProgressed(BackEvent backEvent) { - mBackProgress = backEvent.getProgress(); - // TODO: Update once the interpolation curve spec is finalized. - mBackProgress = - 1 - (1 - mBackProgress) * (1 - mBackProgress) * (1 - - mBackProgress); - if (!mBackInProgress) { - startBack(backEvent); - } else { - updateBackProgress(mBackProgress, backEvent); - } - } + @Override + public void onBackProgressed(BackEvent backEvent) { + mBackProgress = backEvent.getProgress(); + // TODO: Update once the interpolation curve spec is finalized. + mBackProgress = + 1 - (1 - mBackProgress) * (1 - mBackProgress) * (1 + - mBackProgress); + if (!mBackInProgress) { + startBack(backEvent); + } else { + updateBackProgress(mBackProgress, backEvent); + } + } - public void onBackStarted() { } - }); + @Override + public void onBackStarted() { } + }; + SystemUiProxy.INSTANCE.get(mLauncher).setBackToLauncherCallback(mBackCallback); } private void resetPositionAnimated() { @@ -163,7 +166,10 @@ public class LauncherBackAnimationController { /** Unregisters the back to launcher callback in shell. */ public void unregisterBackCallbacks() { - SystemUiProxy.INSTANCE.get(mLauncher).clearBackToLauncherCallback(); + if (mBackCallback != null) { + SystemUiProxy.INSTANCE.get(mLauncher).clearBackToLauncherCallback(mBackCallback); + } + mBackCallback = null; } private void startBack(BackEvent backEvent) { diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java index 5ef89d309a..fc4c23f814 100644 --- a/quickstep/src/com/android/quickstep/SystemUiProxy.java +++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java @@ -847,8 +847,14 @@ public class SystemUiProxy implements ISystemUiProxy, DisplayController.DisplayI } } - /** Clears the previously registered {@link IOnBackInvokedCallback}. */ - public void clearBackToLauncherCallback() { + /** Clears the previously registered {@link IOnBackInvokedCallback}. + * + * @param callback The previously registered callback instance. + */ + public void clearBackToLauncherCallback(IOnBackInvokedCallback callback) { + if (mBackToLauncherCallback != callback) { + return; + } mBackToLauncherCallback = null; if (mBackAnimation == null) { return;