Merge "Import translations. DO NOT MERGE ANYWHERE" into main
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 80da467..5a8fba6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -41,6 +41,7 @@
import com.android.launcher3.logging.InstanceIdSequence;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.taskbar.bubbles.BubbleBarController;
+import com.android.launcher3.taskbar.bubbles.BubbleControllers;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.MultiPropertyFactory;
@@ -86,7 +87,7 @@
private final DeviceProfile.OnDeviceProfileChangeListener mOnDeviceProfileChangeListener =
dp -> {
onStashedInAppChanged(dp);
- adjustHotseatForBubbleBar();
+ postAdjustHotseatForBubbleBar();
if (mControllers != null && mControllers.taskbarViewController != null) {
mControllers.taskbarViewController.onRotationChanged(dp);
}
@@ -275,13 +276,16 @@
}
}
- private void adjustHotseatForBubbleBar() {
+ private void postAdjustHotseatForBubbleBar() {
Hotseat hotseat = mLauncher.getHotseat();
- if (mControllers.bubbleControllers.isEmpty() || hotseat == null) return;
- boolean hiddenForBubbles =
- mControllers.bubbleControllers.get().bubbleBarViewController.isHiddenForNoBubbles();
- if (hiddenForBubbles) return;
- hotseat.post(() -> adjustHotseatForBubbleBar(/* isBubbleBarVisible= */ true));
+ if (hotseat == null || !isBubbleBarVisible()) return;
+ hotseat.post(() -> adjustHotseatForBubbleBar(isBubbleBarVisible()));
+ }
+
+ private boolean isBubbleBarVisible() {
+ BubbleControllers bubbleControllers = mControllers.bubbleControllers.orElse(null);
+ return bubbleControllers != null
+ && bubbleControllers.bubbleBarViewController.isBubbleBarVisible();
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index db5e0d5..b63cf02 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -339,6 +339,7 @@
// clear restored state
mBubbleBarViewController.removeAllBubbles();
mBubbles.clear();
+ mBubbleBarViewController.showOverflow(update.showOverflow);
}
BubbleBarBubble bubbleToSelect = null;
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index d00959e..569dd56 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -1142,6 +1142,7 @@
/** Removes all existing bubble views */
public void removeAllBubbles() {
+ mOverflowAdded = false;
mBarView.removeAllViews();
}
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
index c81edcd..089706f 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
@@ -470,7 +470,7 @@
// Stops requesting focused after first view gets focused.
recentsView.getTaskViewAt(keyboardTaskFocusIndex).requestFocus() ||
recentsView.nextTaskView.requestFocus() ||
- recentsView.getTaskViewAt(0).requestFocus() ||
+ recentsView.getFirstTaskView().requestFocus() ||
recentsView.requestFocus()
}
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
index e334695..20794bf 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
@@ -52,7 +52,10 @@
private val recentsCoroutineScope: CoroutineScope = RecentsDependencies.get()
private val dispatcherProvider: DispatcherProvider = RecentsDependencies.get()
- private lateinit var viewData: TaskThumbnailViewData
+ // This is initialised here and set in onAttachedToWindow because onLayout can be called before
+ // onAttachedToWindow so this property needs to be initialised as it is used below.
+ private var viewData: TaskThumbnailViewData = RecentsDependencies.get(this)
+
private lateinit var viewModel: TaskThumbnailViewModel
private lateinit var viewAttachedScope: CoroutineScope
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index a43c686..4660c51 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -246,13 +246,11 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
-import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@@ -854,72 +852,6 @@
private int mTaskViewCount = 0;
- private final TaskViewsIterable mTaskViewsIterable = new TaskViewsIterable();
-
- public class TaskViewsIterable implements Iterable<TaskView> {
-
- /**
- * Iterates TaskViews when its index inside the RecentsView is needed.
- */
- public void forEachWithIndexInParent(BiConsumer<TaskView, Integer> consumer) {
- int childCount = getChildCount();
- for (int index = 0; index < childCount; index++) {
- if (getChildAt(index) instanceof TaskView taskView) {
- consumer.accept(taskView, index);
- }
- }
- }
-
- @Override
- public TaskViewsIterator iterator() {
- return new TaskViewsIterator();
- }
- }
-
- // An Iterator to iterate all the current TaskViews inside the RecentsView.
- public class TaskViewsIterator implements Iterator<TaskView> {
- // Refers to the index of the `TaskView` that will be returned when `next()` is called.
- private int mNextIndex = 0;
-
- // The "limit" of this iterator. This is the number of children of the RecentsView when
- // the iterator was created. Adding & removing elements will invalidate the iteration
- // anyway (and cause next() to throw) so saving this value will guarantee that the
- // value of hasNext() remains stable and won't flap between true and false when elements
- // are added and removed from the RecentsView.
- private final int mLimit = getChildCount();
-
- TaskViewsIterator() {
- advanceIfNeeded();
- }
-
- @Override
- public boolean hasNext() {
- return mNextIndex < mLimit && mNextIndex < getChildCount();
- }
-
- @Override
- public TaskView next() {
- if (!hasNext()) {
- throw new IndexOutOfBoundsException(
- String.format("mNextIndex: %d, child count: %d", mNextIndex,
- getChildCount()));
- }
- TaskView taskView = requireTaskViewAt(mNextIndex);
- mNextIndex++;
- advanceIfNeeded();
- return taskView;
- }
-
- // Advances `mNextIndex` until it either points to a `TaskView` or to the end of the
- // Iterator.
- private void advanceIfNeeded() {
- while (mNextIndex < mLimit && mNextIndex < getChildCount() && !(getChildAt(
- mNextIndex) instanceof TaskView)) {
- mNextIndex++;
- }
- }
- }
-
@Nullable
public TaskView getFirstTaskView() {
return mUtils.getFirstTaskView();
@@ -2569,7 +2501,7 @@
List<Integer> visibleTaskIds = new ArrayList<>();
// Update the task data for the in/visible children
- getTaskViews().forEachWithIndexInParent((taskView, index) -> {
+ getTaskViews().forEachWithIndexInParent((index, taskView) -> {
List<TaskContainer> containers = taskView.getTaskContainers();
if (containers.isEmpty()) {
return;
@@ -3237,7 +3169,7 @@
* Skips rebalance.
*/
private void updateGridProperties() {
- updateGridProperties(Integer.MAX_VALUE);
+ updateGridProperties(null);
}
/**
@@ -3247,10 +3179,10 @@
* This method only calculates the potential position and depends on {@link #setGridProgress} to
* apply the actual scaling and translation.
*
- * @param startRebalanceAfter which view index to start rebalancing from. Use Integer.MAX_VALUE
- * to skip rebalance
+ * @param lastVisibleTaskViewDuringDismiss which TaskView to start rebalancing from. Use
+ * `null` to skip rebalance.
*/
- private void updateGridProperties(int startRebalanceAfter) {
+ private void updateGridProperties(TaskView lastVisibleTaskViewDuringDismiss) {
if (!hasTaskViews()) {
return;
}
@@ -3263,19 +3195,10 @@
float topAccumulatedTranslationX = 0;
float bottomAccumulatedTranslationX = 0;
- // Contains whether the child index is in top or bottom of grid (for non-focused task)
- // Different from mTopRowIdSet, which contains the taskViewId of what task is in top row
- IntSet topSet = new IntSet();
- IntSet bottomSet = new IntSet();
-
- final int taskCount = getTaskViewCount();
- // Horizontal grid translation for each task
- float[] gridTranslations = new float[taskCount];
+ // Horizontal grid translation for each task.
+ Map<TaskView, Float> gridTranslations = new HashMap<>();
TaskView lastLargeTaskView = mUtils.getLastLargeTaskView();
- int lastLargeTaskIndex =
- (lastLargeTaskView == null) ? Integer.MAX_VALUE : indexOfChild(lastLargeTaskView);
- Set<Integer> largeTasksIndices = new HashSet<>();
int focusedTaskShift = 0;
int largeTaskWidthAndSpacing = 0;
int snappedTaskRowWidth = 0;
@@ -3288,29 +3211,46 @@
if (!mAnyTaskHasBeenDismissed) {
mTopRowIdSet.clear();
}
- for (int i = 0; i < taskCount; i++) {
- TaskView taskView = requireTaskViewAt(i);
+
+ // Consecutive task views in the top row or bottom row, which means another one set will
+ // be cleared up while starting to add TaskViews to one of them. Also means only one of
+ // them can be non-empty at most.
+ Set<TaskView> lastTopTaskViews = new HashSet<>();
+ Set<TaskView> lastBottomTaskViews = new HashSet<>();
+
+ int largeTasksCount = 0;
+ // True if the last large TaskView has been visited during the TaskViews iteration.
+ boolean encounteredLastLargeTaskView = false;
+ // True if the highest index visible TaskView has been visited during the TaskViews
+ // iteration.
+ boolean encounteredLastVisibleTaskView = false;
+ for (TaskView taskView : getTaskViews()) {
+ if (taskView == lastLargeTaskView) {
+ encounteredLastLargeTaskView = true;
+ }
+ if (taskView == lastVisibleTaskViewDuringDismiss) {
+ encounteredLastVisibleTaskView = true;
+ }
+ float gridTranslation = 0f;
int taskWidthAndSpacing = taskView.getLayoutParams().width + mPageSpacing;
// Evenly distribute tasks between rows unless rearranging due to task dismissal, in
// which case keep tasks in their respective rows. For the running task, don't join
// the grid.
- boolean isLargeTile = taskView.isLargeTile();
-
- if (isLargeTile) {
+ if (taskView.isLargeTile()) {
+ largeTasksCount++;
// DesktopTaskView`s are hidden during split select state, so we shouldn't count
// them when calculating row width.
if (!(taskView instanceof DesktopTaskView && isSplitSelectionActive())) {
topRowWidth += taskWidthAndSpacing;
bottomRowWidth += taskWidthAndSpacing;
}
- gridTranslations[i] += focusedTaskShift;
- gridTranslations[i] += mIsRtl ? taskWidthAndSpacing : -taskWidthAndSpacing;
+ gridTranslation += focusedTaskShift;
+ gridTranslation += mIsRtl ? taskWidthAndSpacing : -taskWidthAndSpacing;
// Center view vertically in case it's from different orientation.
taskView.setGridTranslationY((mLastComputedTaskSize.height() + taskTopMargin
- taskView.getLayoutParams().height) / 2f);
- largeTasksIndices.add(i);
largeTaskWidthAndSpacing = taskWidthAndSpacing;
if (taskView == snappedTaskView) {
@@ -3318,9 +3258,9 @@
snappedTaskRowWidth = taskWidthAndSpacing;
}
} else {
- if (i > lastLargeTaskIndex) {
+ if (encounteredLastLargeTaskView) {
// For tasks after the last large task, shift by large task's width and spacing.
- gridTranslations[i] +=
+ gridTranslation +=
mIsRtl ? largeTaskWidthAndSpacing : -largeTaskWidthAndSpacing;
} else {
// For task before the focused task, accumulate the width and spacing to
@@ -3329,10 +3269,10 @@
}
int taskViewId = taskView.getTaskViewId();
- // Rebalance the grid starting after a certain index
boolean isTopRow;
if (mAnyTaskHasBeenDismissed) {
- if (i > startRebalanceAfter) {
+ // Rebalance the grid starting after a certain index.
+ if (encounteredLastVisibleTaskView) {
mTopRowIdSet.remove(taskViewId);
isTopRow = topRowWidth <= bottomRowWidth;
} else {
@@ -3349,47 +3289,43 @@
} else {
topRowWidth += taskWidthAndSpacing;
}
- topSet.add(i);
mTopRowIdSet.add(taskViewId);
-
taskView.setGridTranslationY(mTaskGridVerticalDiff);
// Move horizontally into empty space.
float widthOffset = 0;
- for (int j = i - 1; !topSet.contains(j) && j >= 0; j--) {
- if (largeTasksIndices.contains(j)) {
- continue;
- }
- widthOffset += requireTaskViewAt(j).getLayoutParams().width + mPageSpacing;
+ for (TaskView bottomTaskView : lastBottomTaskViews) {
+ widthOffset += bottomTaskView.getLayoutParams().width + mPageSpacing;
}
float currentTaskTranslationX = mIsRtl ? widthOffset : -widthOffset;
- gridTranslations[i] += topAccumulatedTranslationX + currentTaskTranslationX;
+ gridTranslation += topAccumulatedTranslationX + currentTaskTranslationX;
topAccumulatedTranslationX += currentTaskTranslationX;
+ lastTopTaskViews.add(taskView);
+ lastBottomTaskViews.clear();
} else {
bottomRowWidth += taskWidthAndSpacing;
- bottomSet.add(i);
// Move into bottom row.
taskView.setGridTranslationY(mTopBottomRowHeightDiff + mTaskGridVerticalDiff);
// Move horizontally into empty space.
float widthOffset = 0;
- for (int j = i - 1; !bottomSet.contains(j) && j >= 0; j--) {
- if (largeTasksIndices.contains(j)) {
- continue;
- }
- widthOffset += requireTaskViewAt(j).getLayoutParams().width + mPageSpacing;
+ for (TaskView topTaskView : lastTopTaskViews) {
+ widthOffset += topTaskView.getLayoutParams().width + mPageSpacing;
}
float currentTaskTranslationX = mIsRtl ? widthOffset : -widthOffset;
- gridTranslations[i] += bottomAccumulatedTranslationX + currentTaskTranslationX;
+ gridTranslation += bottomAccumulatedTranslationX + currentTaskTranslationX;
bottomAccumulatedTranslationX += currentTaskTranslationX;
+ lastBottomTaskViews.add(taskView);
+ lastTopTaskViews.clear();
}
if (taskView == snappedTaskView) {
snappedTaskRowWidth = isTopRow ? topRowWidth : bottomRowWidth;
}
}
+ gridTranslations.put(taskView, gridTranslation);
}
// We need to maintain snapped task's page scroll invariant between quick switch and
@@ -3400,22 +3336,22 @@
if (snappedTaskView != null) {
snappedTaskNonGridScrollAdjustment = snappedTaskView.getScrollAdjustment(
/*gridEnabled=*/false);
- snappedTaskGridTranslationX = gridTranslations[snappedPage];
+ snappedTaskGridTranslationX = gridTranslations.get(snappedTaskView);
}
// Use the accumulated translation of the row containing the last task.
- float clearAllAccumulatedTranslation = topSet.contains(taskCount - 1)
+ float clearAllAccumulatedTranslation = !lastTopTaskViews.isEmpty()
? topAccumulatedTranslationX : bottomAccumulatedTranslationX;
// If the last task is on the shorter row, ClearAllButton will embed into the shorter row
// which is not what we want. Compensate the width difference of the 2 rows in that case.
float shorterRowCompensation = 0;
if (topRowWidth <= bottomRowWidth) {
- if (topSet.contains(taskCount - 1)) {
+ if (!lastTopTaskViews.isEmpty()) {
shorterRowCompensation = bottomRowWidth - topRowWidth;
}
} else {
- if (bottomSet.contains(taskCount - 1)) {
+ if (!lastBottomTaskViews.isEmpty()) {
shorterRowCompensation = topRowWidth - bottomRowWidth;
}
}
@@ -3431,8 +3367,7 @@
// for ClearAllButton translation. The space at the left side of the large task will be
// empty and it should be move ClearAllButton further away as well.
// TODO(b/359573248): Validate the translation for ClearAllButton for grid only.
- boolean hasOnlyLargeTasks = taskCount == largeTasksIndices.size();
- if (enableLargeDesktopWindowingTile() && hasOnlyLargeTasks) {
+ if (enableLargeDesktopWindowingTile() && largeTasksCount == getTaskViewCount()) {
longRowWidth = largeTaskWidthAndSpacing;
}
@@ -3456,7 +3391,7 @@
float clearAllTotalTranslationX =
clearAllAccumulatedTranslation + clearAllShorterRowCompensation
+ clearAllShortTotalWidthTranslation + snappedTaskNonGridScrollAdjustment;
- if (!largeTasksIndices.isEmpty()) {
+ if (largeTasksCount > 0) {
// Shift by focused task's width and spacing if a task is focused.
clearAllTotalTranslationX +=
mIsRtl ? largeTaskWidthAndSpacing : -largeTaskWidthAndSpacing;
@@ -3480,10 +3415,10 @@
}
}
- for (int i = 0; i < taskCount; i++) {
- TaskView taskView = requireTaskViewAt(i);
- taskView.setGridTranslationX(gridTranslations[i] - snappedTaskGridTranslationX
- + snappedTaskNonGridScrollAdjustment);
+ for (TaskView taskView : getTaskViews()) {
+ taskView.setGridTranslationX(
+ gridTranslations.get(taskView) - snappedTaskGridTranslationX
+ + snappedTaskNonGridScrollAdjustment);
}
final TaskView runningTask = getRunningTaskView();
@@ -4222,7 +4157,8 @@
// Rebalance tasks in the grid
int highestVisibleTaskIndex = getHighestVisibleTaskIndex();
if (highestVisibleTaskIndex < Integer.MAX_VALUE) {
- TaskView taskView = requireTaskViewAt(highestVisibleTaskIndex);
+ final TaskView taskView = requireTaskViewAt(
+ highestVisibleTaskIndex);
boolean shouldRebalance;
int screenStart = getPagedOrientationHandler().getPrimaryScroll(
@@ -4250,7 +4186,7 @@
}
if (shouldRebalance) {
- updateGridProperties(highestVisibleTaskIndex);
+ updateGridProperties(taskView);
updateScrollSynchronously();
}
}
@@ -4805,8 +4741,8 @@
/**
* Returns iterable [TaskView] children.
*/
- public TaskViewsIterable getTaskViews() {
- return mTaskViewsIterable;
+ public RecentsViewUtils.TaskViewsIterable getTaskViews() {
+ return mUtils.getTaskViews();
}
public void setOnEmptyMessageUpdatedListener(OnEmptyMessageUpdatedListener listener) {
@@ -5239,7 +5175,7 @@
SplitAnimationTimings timings = AnimUtils.getDeviceOverviewToSplitTimings(
mContainer.getDeviceProfile().isTablet);
if (enableLargeDesktopWindowingTile()) {
- getTaskViews().forEachWithIndexInParent((taskView, index) -> {
+ getTaskViews().forEachWithIndexInParent((index, taskView) -> {
if (taskView instanceof DesktopTaskView) {
// Setting pivot to scale down from screen centre.
if (isTaskViewVisible(taskView)) {
@@ -6188,7 +6124,7 @@
}
int lastTaskScroll = getLastTaskScroll(clearAllScroll, clearAllWidth);
- getTaskViews().forEachWithIndexInParent((taskView, index) -> {
+ getTaskViews().forEachWithIndexInParent((index, taskView) -> {
float scrollDiff = taskView.getScrollAdjustment(showAsGrid);
int pageScroll = newPageScrolls[index] + Math.round(scrollDiff);
if ((mIsRtl && pageScroll < lastTaskScroll)
diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt b/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt
index ccf22ce..3ac3349 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt
+++ b/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt
@@ -22,12 +22,15 @@
import com.android.quickstep.util.GroupTask
import com.android.quickstep.views.RecentsView.RUNNING_TASK_ATTACH_ALPHA
import com.android.systemui.shared.recents.model.ThumbnailData
+import java.util.function.BiConsumer
/**
* Helper class for [RecentsView]. This util class contains refactored and extracted functions from
* RecentsView to facilitate the implementation of unit tests.
*/
class RecentsViewUtils(private val recentsView: RecentsView<*, *>) {
+ val taskViews = TaskViewsIterable(recentsView)
+
/** Takes a screenshot of all [taskView] and return map of taskId to the screenshot */
fun screenshotTasks(taskView: TaskView): Map<Int, ThumbnailData> {
val recentsAnimationController = recentsView.recentsAnimationController ?: return emptyMap()
@@ -47,27 +50,37 @@
return otherTasks + desktopTasks
}
+ class TaskViewsIterable(val recentsView: RecentsView<*, *>) : Iterable<TaskView> {
+ /** Iterates TaskViews when its index inside the RecentsView is needed. */
+ fun forEachWithIndexInParent(consumer: BiConsumer<Int, TaskView>) {
+ recentsView.children.forEachIndexed { index, child ->
+ (child as? TaskView)?.let { consumer.accept(index, it) }
+ }
+ }
+
+ override fun iterator(): Iterator<TaskView> =
+ recentsView.children.mapNotNull { it as? TaskView }.iterator()
+ }
+
/** Counts [TaskView]s that are [DesktopTaskView] instances. */
- fun getDesktopTaskViewCount(): Int = recentsView.taskViews.count { it is DesktopTaskView }
+ fun getDesktopTaskViewCount(): Int = taskViews.count { it is DesktopTaskView }
/** Returns a list of all large TaskView Ids from [TaskView]s */
- fun getLargeTaskViewIds(): List<Int> =
- recentsView.taskViews.filter { it.isLargeTile }.map { it.taskViewId }
+ fun getLargeTaskViewIds(): List<Int> = taskViews.filter { it.isLargeTile }.map { it.taskViewId }
/** Counts [TaskView]s that are large tiles. */
- fun getLargeTileCount(): Int = recentsView.taskViews.count { it.isLargeTile }
+ fun getLargeTileCount(): Int = taskViews.count { it.isLargeTile }
/** Returns the first TaskView that should be displayed as a large tile. */
fun getFirstLargeTaskView(): TaskView? =
- recentsView.taskViews.firstOrNull {
+ taskViews.firstOrNull {
it.isLargeTile && !(recentsView.isSplitSelectionActive && it is DesktopTaskView)
}
/** Returns the expected focus task. */
fun getExpectedFocusedTask(): TaskView? =
- if (enableLargeDesktopWindowingTile())
- recentsView.taskViews.firstOrNull { it !is DesktopTaskView }
- else recentsView.taskViews.firstOrNull()
+ if (enableLargeDesktopWindowingTile()) taskViews.firstOrNull { it !is DesktopTaskView }
+ else taskViews.firstOrNull()
/**
* Returns the [TaskView] that should be the current page during task binding, in the following
@@ -81,20 +94,20 @@
fun getExpectedCurrentTask(runningTaskView: TaskView?, focusedTaskView: TaskView?): TaskView? =
runningTaskView
?: focusedTaskView
- ?: recentsView.taskViews.firstOrNull { it !is DesktopTaskView }
- ?: recentsView.taskViews.lastOrNull()
+ ?: taskViews.firstOrNull { it !is DesktopTaskView }
+ ?: taskViews.lastOrNull()
/** Returns the first TaskView if it exists, or null otherwise. */
- fun getFirstTaskView(): TaskView? = recentsView.taskViews.firstOrNull()
+ fun getFirstTaskView(): TaskView? = taskViews.firstOrNull()
/** Returns the last TaskView if it exists, or null otherwise. */
- fun getLastTaskView(): TaskView? = recentsView.taskViews.lastOrNull()
+ fun getLastTaskView(): TaskView? = taskViews.lastOrNull()
/** Returns the first TaskView that is not large */
- fun getFirstSmallTaskView(): TaskView? = recentsView.taskViews.firstOrNull { !it.isLargeTile }
+ fun getFirstSmallTaskView(): TaskView? = taskViews.firstOrNull { !it.isLargeTile }
/** Returns the last TaskView that should be displayed as a large tile. */
- fun getLastLargeTaskView(): TaskView? = recentsView.taskViews.lastOrNull { it.isLargeTile }
+ fun getLastLargeTaskView(): TaskView? = taskViews.lastOrNull { it.isLargeTile }
/**
* Gets the list of accessibility children. Currently all the children of RecentsViews are
@@ -108,23 +121,23 @@
nonRunningTaskCarouselHidden: Boolean,
runningTaskView: TaskView? = recentsView.runningTaskView,
): TaskView? =
- recentsView.taskViews.firstOrNull {
+ taskViews.firstOrNull {
it.isVisibleInCarousel(runningTaskView, nonRunningTaskCarouselHidden)
}
/** Returns the last [TaskView], with some tasks possibly hidden in the carousel. */
fun getLastTaskViewInCarousel(nonRunningTaskCarouselHidden: Boolean): TaskView? =
- recentsView.taskViews.lastOrNull {
+ taskViews.lastOrNull {
it.isVisibleInCarousel(recentsView.runningTaskView, nonRunningTaskCarouselHidden)
}
/** Returns if any small tasks are fully visible */
fun isAnySmallTaskFullyVisible(): Boolean =
- recentsView.taskViews.any { !it.isLargeTile && recentsView.isTaskViewFullyVisible(it) }
+ taskViews.any { !it.isLargeTile && recentsView.isTaskViewFullyVisible(it) }
/** Apply attachAlpha to all [TaskView] accordingly to different conditions. */
fun applyAttachAlpha(nonRunningTaskCarouselHidden: Boolean) {
- recentsView.taskViews.forEach { taskView ->
+ taskViews.forEach { taskView ->
taskView.attachAlpha =
if (taskView == recentsView.runningTaskView) {
RUNNING_TASK_ATTACH_ALPHA.get(recentsView)
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
index 5471072..2f773b3 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
@@ -245,6 +245,10 @@
animator.onStashStateChangingWhileAnimating()
}
+ // The physics animation test util posts the cancellation to the looper thread, so we have
+ // to wait again and let it finish.
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+
// verify that the hide animation was canceled
assertThat(animatorScheduler.delayedBlock).isNull()
assertThat(animator.isAnimating).isFalse()
@@ -1296,7 +1300,7 @@
animator.animateBubbleInForStashed(updatedBubble, isExpanding = false)
}
- // since animation was interrupted there shouldn`t be additional calls to adjust window
+ // since animation was interrupted there shouldn't be additional calls to adjust window
assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
InstrumentationRegistry.getInstrumentation().runOnMainSync {}
diff --git a/res/layout/work_apps_edu.xml b/res/layout/work_apps_edu.xml
index 0e2c19a..a19d13a 100644
--- a/res/layout/work_apps_edu.xml
+++ b/res/layout/work_apps_edu.xml
@@ -46,6 +46,8 @@
android:layout_width="@dimen/rounded_button_width"
android:layout_height="@dimen/rounded_button_width"
android:layout_marginTop="@dimen/work_edu_card_button_margin_top"
+ android:clickable="true"
+ android:contentDescription="@string/accessibility_close"
android:gravity="center"
android:background="@drawable/inset_rounded_action_button">
<ImageButton
@@ -54,7 +56,7 @@
android:clickable="false"
android:scaleType="centerInside"
android:layout_gravity="center"
- android:contentDescription="@string/accessibility_close"
+ android:importantForAccessibility="no"
android:background="@android:color/transparent"
android:src="@drawable/ic_close_work_edu" />
</FrameLayout>
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index c37b56c..b38efc2 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1569,7 +1569,6 @@
if (!enableAddAppWidgetViaConfigActivityV2() || hostView.getParent() == null) {
mWorkspace.addInScreen(hostView, launcherInfo);
}
- announceForAccessibility(R.string.item_added_to_workspace);
// Show the widget resize frame.
if (hostView instanceof LauncherAppWidgetHostView) {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 69a5a83..a064c88 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -3519,9 +3519,8 @@
@Override
protected boolean canAnnouncePageDescription() {
- // Disable announcements while overscrolling potentially to overlay screen because if we end
- // up on the overlay screen, it will take care of announcing itself.
- return Float.compare(mOverlayProgress, 0f) == 0;
+ // b/383247157: Disable disruptive home screen page announcement
+ return false;
}
@Override
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index ba6ed66..81d6631 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -305,7 +305,6 @@
info.spanX, info.spanY);
host.requestLayout();
mContext.getModelWriter().updateItemInDatabase(info);
- announceConfirmation(mContext.getString(R.string.widget_resized, info.spanX, info.spanY));
return true;
}
diff --git a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
index 84d6a6f..65b0662 100644
--- a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
+++ b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
@@ -114,9 +114,7 @@
LauncherAccessibilityDelegate.DragInfo dragInfo = mDelegate.getDragInfo();
View child = mView.getChildAt(x, y);
- if (child == null || child == dragInfo.item) {
- return mContext.getString(R.string.item_moved);
- } else {
+ if (child != null && child != dragInfo.item) {
ItemInfo info = (ItemInfo) child.getTag();
if (Folder.willAccept(info)) {
return mContext.getString(R.string.folder_created);
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 5defef3..e68e3c9 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -680,6 +680,7 @@
closeOpenFolder(openFolder);
mContent.bindItems(items);
+ mContent.setCanAnnouncePageDescriptionForFolder(true);
centerAboutIcon();
mItemsInvalidated = true;
updateTextViewFocus();
@@ -813,6 +814,7 @@
@Override
protected void handleClose(boolean animate) {
mIsOpen = false;
+ mContent.setCanAnnouncePageDescriptionForFolder(false);
if (!animate && mCurrentAnimator != null && mCurrentAnimator.isRunning()) {
mCurrentAnimator.cancel();
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index fe26194..8d751e6 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -100,6 +100,8 @@
// animating or is open.
private boolean mViewsBound = false;
+ private boolean mCanAnnouncePageDescription;
+
public FolderPagedView(Context context, AttributeSet attrs) {
this(
context,
@@ -170,6 +172,19 @@
mViewsBound = true;
}
+ void setCanAnnouncePageDescriptionForFolder(boolean canAnnounce) {
+ mCanAnnouncePageDescription = canAnnounce;
+ }
+
+ private boolean canAnnouncePageDescriptionForFolder() {
+ return mCanAnnouncePageDescription;
+ }
+
+ @Override
+ protected boolean canAnnouncePageDescription() {
+ return super.canAnnouncePageDescription() && canAnnouncePageDescriptionForFolder();
+ }
+
/**
* Removes all the icons from the folder
*/
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index ab4105c..0ebd69f 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -107,9 +107,9 @@
IconProvider iconProvider) {
super(context, dbFileName, MODEL_EXECUTOR.getLooper(),
idp.fillResIconDpi, idp.iconBitmapSize, true /* inMemoryCache */, iconProvider);
- mLauncherApps = mContext.getSystemService(LauncherApps.class);
- mUserManager = UserCache.INSTANCE.get(mContext);
- mInstantAppResolver = InstantAppResolver.newInstance(mContext);
+ mLauncherApps = context.getSystemService(LauncherApps.class);
+ mUserManager = UserCache.INSTANCE.get(context);
+ mInstantAppResolver = InstantAppResolver.newInstance(context);
mWidgetCategoryBitmapInfos = new SparseArray<>();
mCancelledTask = new CancellableTask(() -> null, MAIN_EXECUTOR, c -> { });
@@ -117,7 +117,7 @@
}
@Override
- protected long getSerialNumberForUser(@NonNull UserHandle user) {
+ public long getSerialNumberForUser(@NonNull UserHandle user) {
return mUserManager.getSerialNumberForUser(user);
}
@@ -129,7 +129,7 @@
@NonNull
@Override
public BaseIconFactory getIconFactory() {
- return LauncherIcons.obtain(mContext);
+ return LauncherIcons.obtain(context);
}
/**
@@ -151,7 +151,7 @@
// This will clear all pending updates
getUpdateHandler();
- mIconDb.close();
+ iconDb.close();
}
/**
@@ -231,7 +231,7 @@
* Fill in {@code info} with the icon for {@code si}
*/
public void getShortcutIcon(ItemInfoWithIcon info, ShortcutInfo si) {
- getShortcutIcon(info, new CacheableShortcutInfo(si, mContext));
+ getShortcutIcon(info, new CacheableShortcutInfo(si, context));
}
/**
@@ -279,7 +279,7 @@
String override = shortcutInfo.getExtras() == null ? null
: shortcutInfo.getExtras().getString(EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE);
if (!TextUtils.isEmpty(override)
- && InstallSessionHelper.INSTANCE.get(mContext)
+ && InstallSessionHelper.INSTANCE.get(context)
.isTrustedPackage(pkg, shortcutInfo.getUserHandle())) {
pkg = override;
} else {
@@ -364,11 +364,11 @@
String componentNameQuery = TextUtils.join(
",", Collections.nCopies(queryParams.length - 1, "?"));
- return mIconDb.query(
- useLowResIcons ? IconDB.COLUMNS_LOW_RES : IconDB.COLUMNS_HIGH_RES,
- IconDB.COLUMN_COMPONENT
+ return iconDb.query(
+ useLowResIcons ? COLUMNS_LOW_RES : COLUMNS_HIGH_RES,
+ COLUMN_COMPONENT
+ " IN ( " + componentNameQuery + " )"
- + " AND " + IconDB.COLUMN_USER + " = ?",
+ + " AND " + COLUMN_USER + " = ?",
queryParams);
}
@@ -428,7 +428,7 @@
/* user = */ sectionKey.first,
/* useLowResIcons = */ sectionKey.second)) {
// Database title and icon loading
- int componentNameColumnIndex = c.getColumnIndexOrThrow(IconDB.COLUMN_COMPONENT);
+ int componentNameColumnIndex = c.getColumnIndexOrThrow(COLUMN_COMPONENT);
while (c.moveToNext()) {
ComponentName cn = ComponentName.unflattenFromString(
c.getString(componentNameColumnIndex));
@@ -525,9 +525,9 @@
return;
}
- WidgetSection widgetSection = WidgetSections.getWidgetSections(mContext)
+ WidgetSection widgetSection = WidgetSections.getWidgetSections(context)
.get(infoInOut.widgetCategory);
- infoInOut.title = mContext.getString(widgetSection.mSectionTitle);
+ infoInOut.title = context.getString(widgetSection.mSectionTitle);
infoInOut.contentDescription = getUserBadgedLabel(infoInOut.title, infoInOut.user);
final BitmapInfo cachedBitmap = mWidgetCategoryBitmapInfos.get(infoInOut.widgetCategory);
if (cachedBitmap != null) {
@@ -535,9 +535,9 @@
return;
}
- try (LauncherIcons li = LauncherIcons.obtain(mContext)) {
+ try (LauncherIcons li = LauncherIcons.obtain(context)) {
final BitmapInfo tempBitmap = li.createBadgedIconBitmap(
- mContext.getDrawable(widgetSection.mSectionDrawable),
+ context.getDrawable(widgetSection.mSectionDrawable),
new BaseIconFactory.IconOptions());
mWidgetCategoryBitmapInfos.put(infoInOut.widgetCategory, tempBitmap);
infoInOut.bitmap = getBadgedIcon(tempBitmap, infoInOut.user);
@@ -606,7 +606,7 @@
/** Log persistently to FileLog.d for debugging. */
@Override
- protected void logdPersistently(String tag, String message, @Nullable Exception e) {
- FileLog.d(tag, message, e);
+ protected void logPersistently(@NonNull String message, @Nullable Exception e) {
+ FileLog.d(BaseIconCache.TAG, message, e);
}
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java b/src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java
index d84a219..d042b1d 100644
--- a/src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java
+++ b/src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java
@@ -290,16 +290,28 @@
}
setCurrentPage(requestedPage);
mPageIndicator.setActiveMarker(requestedPage);
- mRecommendationPageTitle.setText(mCategoryTitles.get(requestedPage));
+ updatePageTitle(requestedPage);
}
}
@Override
+ protected boolean canAnnouncePageDescription() {
+ // Disable announcement as our page title reads out the needed page description
+ return false;
+ }
+
+ private void updatePageTitle(int requestedPage) {
+ String title = mCategoryTitles.get(requestedPage);
+ mRecommendationPageTitle.setText(title);
+ mRecommendationPageTitle.setContentDescription(title + ", " + getCurrentPageDescription());
+ }
+
+ @Override
protected void notifyPageSwitchListener(int prevPage) {
if (getPageCount() > 1) {
// Since the title is outside the paging scroll, we update the title on page switch.
int nextPage = getNextPage();
- mRecommendationPageTitle.setText(mCategoryTitles.get(nextPage));
+ updatePageTitle(nextPage);
mPageSwitchListeners.forEach(listener -> listener.accept(nextPage));
super.notifyPageSwitchListener(prevPage);
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheUpdateHandlerTest.kt b/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheUpdateHandlerTest.kt
index bae74c8..9dbed74 100644
--- a/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheUpdateHandlerTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheUpdateHandlerTest.kt
@@ -62,7 +62,11 @@
private var cursor =
MatrixCursor(
- arrayOf(IconDB.COLUMN_ROWID, IconDB.COLUMN_COMPONENT, IconDB.COLUMN_FRESHNESS_ID)
+ arrayOf(
+ BaseIconCache.COLUMN_ROWID,
+ BaseIconCache.COLUMN_COMPONENT,
+ BaseIconCache.COLUMN_FRESHNESS_ID,
+ )
)
private lateinit var updateHandlerUnderTest: IconCacheUpdateHandler
diff --git a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
index 4d181ff..d2229c4 100644
--- a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
@@ -124,7 +124,7 @@
`when`(app.invariantDeviceProfile).thenReturn(idp)
`when`(launcherBinder.newIdleLock(any())).thenReturn(idleLock)
`when`(idleLock.awaitLocked(1000)).thenReturn(false)
- `when`(iconCache.updateHandler).thenReturn(iconCacheUpdateHandler)
+ `when`(iconCache.getUpdateHandler()).thenReturn(iconCacheUpdateHandler)
`when`(widgetsFilterDataProvider.getDefaultWidgetsFilter()).thenReturn(Predicate { true })
context.putObject(UserCache.INSTANCE, userCache)