Merge changes I4532e429,I532645de into ub-launcher3-qt-future-dev
* changes:
Defer listening on widget host until after the state transition ends
Migrate to using DefaultDisplay
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
index 4f97180..25cc33d 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
@@ -172,8 +172,6 @@
AnimatorSetBuilder builder = new AnimatorSetBuilder();
// setRecentsAttachedToAppWindow() will animate recents out.
builder.addFlag(AnimatorSetBuilder.FLAG_DONT_ANIMATE_OVERVIEW);
- // We want to keep all apps content as GONE to avoid relayout during home animation.
- builder.addFlag(AnimatorSetBuilder.FLAG_DONT_UPDATE_ALL_APPS_VISIBILITY);
stateManager.createAtomicAnimation(BACKGROUND_APP, NORMAL, builder, ANIM_ALL, 0);
builder.build().start();
@@ -202,9 +200,6 @@
// This ensures then the next swipe up to all-apps starts from scroll 0.
activity.getAppsView().reset(false /* animate */);
- // Optimization, hide the all apps view to prevent layout while initializing
- activity.getAppsView().getContentView().setVisibility(View.GONE);
-
return new AnimationFactory() {
private ShelfAnimState mShelfState;
private boolean mIsAttachedToWindow;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java
index 38b5a13..346969e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java
@@ -1,3 +1,4 @@
+
/*
* Copyright (C) 2019 The Android Open Source Project
*
@@ -82,7 +83,8 @@
private int mDirection;
private ActivityControlHelper mActivityControlHelper;
- private final float mDistThreshold;
+ private final float mDragDistThreshold;
+ private final float mFlingDistThreshold;
private final long mTimeThreshold;
private final int mAngleThreshold;
private final float mSquaredSlop;
@@ -97,7 +99,8 @@
final Resources res = context.getResources();
mContext = context;
mSysUiProxy = systemUiProxy;
- mDistThreshold = res.getDimension(R.dimen.gestures_assistant_drag_threshold);
+ mDragDistThreshold = res.getDimension(R.dimen.gestures_assistant_drag_threshold);
+ mFlingDistThreshold = res.getDimension(R.dimen.gestures_assistant_fling_threshold);
mTimeThreshold = res.getInteger(R.integer.assistant_gesture_min_time_threshold);
mAngleThreshold = res.getInteger(R.integer.assistant_gesture_corner_deg_threshold);
@@ -117,8 +120,6 @@
@Override
public void onMotionEvent(MotionEvent ev) {
// TODO add logging
- mGestureDetector.onTouchEvent(ev);
-
switch (ev.getActionMasked()) {
case ACTION_DOWN: {
mActivePointerId = ev.getPointerId(0);
@@ -213,6 +214,8 @@
break;
}
+ mGestureDetector.onTouchEvent(ev);
+
if (mState != STATE_ACTIVE) {
mDelegate.onMotionEvent(ev);
}
@@ -220,9 +223,9 @@
private void updateAssistantProgress() {
if (!mLaunchedAssistant) {
- mLastProgress = Math.min(mDistance * 1f / mDistThreshold, 1) * mTimeFraction;
+ mLastProgress = Math.min(mDistance * 1f / mDragDistThreshold, 1) * mTimeFraction;
try {
- if (mDistance >= mDistThreshold && mTimeFraction >= 1) {
+ if (mDistance >= mDragDistThreshold && mTimeFraction >= 1) {
mSysUiProxy.onAssistantGestureCompletion(0);
startAssistantInternal(SWIPE);
@@ -271,7 +274,9 @@
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (isValidAssistantGestureAngle(velocityX, -velocityY)
- && !mLaunchedAssistant && mState != STATE_DELEGATE_ACTIVE) {
+ && mDistance >= mFlingDistThreshold
+ && !mLaunchedAssistant
+ && mState != STATE_DELEGATE_ACTIVE) {
mLastProgress = 1;
try {
mSysUiProxy.onAssistantGestureCompletion(
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index 1069bed..1aa5365 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -29,6 +29,7 @@
import androidx.annotation.Nullable;
+import com.android.launcher3.BubbleTextView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
@@ -40,7 +41,9 @@
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.anim.SpringObjectAnimator;
+import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.graphics.OverviewScrim;
+import com.android.launcher3.views.IconLabelDotView;
import java.util.ArrayList;
import java.util.List;
@@ -62,7 +65,9 @@
private final float mVelocity;
private final float mSpringTransY;
- private final View mViewToIgnore;
+
+ // The original view of the {@link FloatingIconView}.
+ private final View mOriginalView;
private final List<Animator> mAnimators = new ArrayList<>();
@@ -72,9 +77,7 @@
public StaggeredWorkspaceAnim(Launcher launcher, @Nullable View floatingViewOriginalView,
float velocity) {
mVelocity = velocity;
- // We ignore this view since it's visibility and position is controlled by
- // the FloatingIconView.
- mViewToIgnore = floatingViewOriginalView;
+ mOriginalView = floatingViewOriginalView;
// Scale the translationY based on the initial velocity to better sync the workspace items
// with the floating view.
@@ -86,16 +89,21 @@
Workspace workspace = launcher.getWorkspace();
CellLayout cellLayout = (CellLayout) workspace.getChildAt(workspace.getCurrentPage());
ShortcutAndWidgetContainer currentPage = cellLayout.getShortcutsAndWidgets();
+ ViewGroup hotseat = launcher.getHotseat();
boolean workspaceClipChildren = workspace.getClipChildren();
boolean workspaceClipToPadding = workspace.getClipToPadding();
boolean cellLayoutClipChildren = cellLayout.getClipChildren();
boolean cellLayoutClipToPadding = cellLayout.getClipToPadding();
+ boolean hotseatClipChildren = hotseat.getClipChildren();
+ boolean hotseatClipToPadding = hotseat.getClipToPadding();
workspace.setClipChildren(false);
workspace.setClipToPadding(false);
cellLayout.setClipChildren(false);
cellLayout.setClipToPadding(false);
+ hotseat.setClipChildren(false);
+ hotseat.setClipToPadding(false);
// Hotseat and QSB takes up two additional rows.
int totalRows = grid.inv.numRows + (grid.isVerticalBarLayout() ? 0 : 2);
@@ -108,16 +116,18 @@
}
// Set up springs for the hotseat and qsb.
+ ViewGroup hotseatChild = (ViewGroup) hotseat.getChildAt(0);
if (grid.isVerticalBarLayout()) {
- ViewGroup hotseat = (ViewGroup) launcher.getHotseat().getChildAt(0);
- for (int i = hotseat.getChildCount() - 1; i >= 0; i--) {
- View child = hotseat.getChildAt(i);
+ for (int i = hotseatChild.getChildCount() - 1; i >= 0; i--) {
+ View child = hotseatChild.getChildAt(i);
CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) child.getLayoutParams());
addStaggeredAnimationForView(child, lp.cellY + 1, totalRows);
}
} else {
- View hotseat = launcher.getHotseat().getChildAt(0);
- addStaggeredAnimationForView(hotseat, grid.inv.numRows + 1, totalRows);
+ for (int i = hotseatChild.getChildCount() - 1; i >= 0; i--) {
+ View child = hotseatChild.getChildAt(i);
+ addStaggeredAnimationForView(child, grid.inv.numRows + 1, totalRows);
+ }
View qsb = launcher.findViewById(R.id.search_container_all_apps);
addStaggeredAnimationForView(qsb, grid.inv.numRows + 2, totalRows);
@@ -140,6 +150,8 @@
workspace.setClipToPadding(workspaceClipToPadding);
cellLayout.setClipChildren(cellLayoutClipChildren);
cellLayout.setClipToPadding(cellLayoutClipToPadding);
+ hotseat.setClipChildren(hotseatClipChildren);
+ hotseat.setClipToPadding(hotseatClipToPadding);
}
};
@@ -180,16 +192,35 @@
springTransY.setStartDelay(startDelay);
mAnimators.add(springTransY);
- if (v == mViewToIgnore) {
- return;
+ ObjectAnimator alpha = getAlphaAnimator(v, startDelay);
+ if (v == mOriginalView) {
+ // For IconLabelDotViews, we just want the label to fade in.
+ // Icon, badge, and dots will animate in separately (controlled via FloatingIconView)
+ if (v instanceof IconLabelDotView) {
+ alpha.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ IconLabelDotView view = (IconLabelDotView) v;
+ view.setIconVisible(false);
+ view.setForceHideDot(true);
+ }
+ });
+ } else {
+ return;
+ }
}
v.setAlpha(0);
+ mAnimators.add(alpha);
+ }
+
+ private ObjectAnimator getAlphaAnimator(View v, long startDelay) {
ObjectAnimator alpha = ObjectAnimator.ofFloat(v, View.ALPHA, 0f, 1f);
alpha.setInterpolator(LINEAR);
alpha.setDuration(ALPHA_DURATION_MS);
alpha.setStartDelay(startDelay);
- mAnimators.add(alpha);
+ return alpha;
+
}
private void addScrimAnimationForState(Launcher launcher, LauncherState state, long duration) {
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index b0968f9..78424ca 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -69,6 +69,7 @@
<!-- Distance from the vertical edges of the screen in which assist gestures are recognized -->
<dimen name="gestures_assistant_width">48dp</dimen>
<dimen name="gestures_assistant_drag_threshold">55dp</dimen>
+ <dimen name="gestures_assistant_fling_threshold">55dp</dimen>
<!-- Distance to move elements when swiping up to go home from launcher -->
<dimen name="home_pullback_distance">28dp</dimen>
diff --git a/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java b/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
index ec3d49a..a7c33a9 100644
--- a/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
+++ b/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
@@ -69,10 +69,9 @@
private DigitalWellBeingToast getToast() {
executeOnLauncher(launcher -> launcher.getStateManager().goToState(OVERVIEW));
waitForState("Launcher internal state didn't switch to Overview", OVERVIEW);
- waitForLauncherCondition("No latest task", launcher -> getLatestTask(launcher) != null);
+ final TaskView task = getOnceNotNull("No latest task", launcher -> getLatestTask(launcher));
return getFromLauncher(launcher -> {
- final TaskView task = getLatestTask(launcher);
assertTrue("Latest task is not Calculator",
CALCULATOR_PACKAGE.equals(task.getTask().getTopComponent().getPackageName()));
return task.getDigitalWellBeingToast();
diff --git a/res/layout/folder_application.xml b/res/layout/folder_application.xml
index c156e11..32a5419 100644
--- a/res/layout/folder_application.xml
+++ b/res/layout/folder_application.xml
@@ -20,4 +20,5 @@
style="@style/BaseIcon"
android:textColor="?attr/folderTextColor"
android:includeFontPadding="false"
+ android:hapticFeedbackEnabled="false"
launcher:iconDisplay="folder" />
diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java
index c84be4d..864fa6e 100644
--- a/src/com/android/launcher3/BaseRecyclerView.java
+++ b/src/com/android/launcher3/BaseRecyclerView.java
@@ -22,6 +22,7 @@
import android.view.View;
import android.view.ViewGroup;
+import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.views.RecyclerViewFastScroller;
import androidx.recyclerview.widget.RecyclerView;
@@ -171,4 +172,13 @@
* <p>Override in each subclass of this base class.
*/
public void onFastScrollCompleted() {}
+
+ @Override
+ public void onScrollStateChanged(int state) {
+ super.onScrollStateChanged(state);
+
+ if (state == SCROLL_STATE_IDLE) {
+ AccessibilityManagerCompat.sendScrollFinishedEventToTest(getContext());
+ }
+ }
}
\ No newline at end of file
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 22c69f5..b113249 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -32,7 +32,6 @@
import android.graphics.drawable.Drawable;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
-import android.util.Log;
import android.util.Property;
import android.util.TypedValue;
import android.view.KeyEvent;
@@ -54,8 +53,8 @@
import com.android.launcher3.icons.IconCache.IconLoadRequest;
import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
import com.android.launcher3.model.PackageItemInfo;
-import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.views.IconLabelDotView;
import java.text.NumberFormat;
@@ -64,7 +63,8 @@
* because we want to make the bubble taller than the text and TextView's clip is
* too aggressive.
*/
-public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, OnResumeCallback {
+public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, OnResumeCallback,
+ IconLabelDotView {
private static final int DISPLAY_WORKSPACE = 0;
private static final int DISPLAY_ALL_APPS = 1;
@@ -413,7 +413,8 @@
}
}
- public void forceHideDot(boolean forceHideDot) {
+ @Override
+ public void setForceHideDot(boolean forceHideDot) {
if (mForceHideDot == forceHideDot) {
return;
}
@@ -602,6 +603,7 @@
}
}
+ @Override
public void setIconVisible(boolean visible) {
mIsIconVisible = visible;
Drawable icon = visible ? mIcon : new ColorDrawable(Color.TRANSPARENT);
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index 7ab88a0..a90025e 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -142,8 +142,11 @@
@Override
public void setAlpha(int alpha) {
- mAlpha = alpha;
- mPaint.setAlpha(alpha);
+ if (mAlpha != alpha) {
+ mAlpha = alpha;
+ mPaint.setAlpha(alpha);
+ invalidateSelf();
+ }
}
@Override
diff --git a/src/com/android/launcher3/FolderInfo.java b/src/com/android/launcher3/FolderInfo.java
index 67d5ab0..e2b7b68 100644
--- a/src/com/android/launcher3/FolderInfo.java
+++ b/src/com/android/launcher3/FolderInfo.java
@@ -93,13 +93,6 @@
itemsChanged(animate);
}
- public void setTitle(CharSequence title) {
- this.title = title;
- for (int i = 0; i < mListeners.size(); i++) {
- mListeners.get(i).onTitleChanged(title);
- }
- }
-
@Override
public void onAddToDatabase(ContentWriter writer) {
super.onAddToDatabase(writer);
@@ -121,18 +114,10 @@
}
}
- public void prepareAutoUpdate() {
- for (int i = 0; i < mListeners.size(); i++) {
- mListeners.get(i).prepareAutoUpdate();
- }
- }
-
public interface FolderListener {
public void onAdd(WorkspaceItemInfo item, int rank);
public void onRemove(WorkspaceItemInfo item);
- public void onTitleChanged(CharSequence title);
public void onItemsChanged(boolean animate);
- public void prepareAutoUpdate();
}
public boolean hasOption(int optionFlag) {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index b73cee4..61d05c1 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -2347,6 +2347,11 @@
// override the previous page so we don't log the page switch.
mWorkspace.setCurrentPage(pageBoundFirst, pageBoundFirst /* overridePrevPage */);
+ // Cache one page worth of icons
+ getViewCache().setCacheSize(R.layout.folder_application,
+ mDeviceProfile.inv.numFolderColumns * mDeviceProfile.inv.numFolderRows);
+ getViewCache().setCacheSize(R.layout.folder_page, 2);
+
TraceHelper.endSection("finishBindingItems");
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 1b757d5..56a8966 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -92,7 +92,6 @@
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.IntArray;
-import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.IntSparseArrayMap;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.PackageUserKey;
@@ -134,9 +133,6 @@
private static final int DEFAULT_PAGE = 0;
- public static final boolean MAP_NO_RECURSE = false;
- public static final boolean MAP_RECURSE = true;
-
private LayoutTransition mLayoutTransition;
@Thunk final WallpaperManager mWallpaperManager;
@@ -2809,7 +2805,7 @@
* Removes all folder listeners
*/
public void removeFolderListeners() {
- mapOverItems(false, new ItemOperator() {
+ mapOverItems(new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View view) {
if (view instanceof FolderIcon) {
@@ -2961,7 +2957,7 @@
public View getFirstMatch(final ItemOperator operator) {
final View[] value = new View[1];
- mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
+ mapOverItems(new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View v) {
if (operator.evaluate(info, v)) {
@@ -2984,7 +2980,7 @@
final View[] matches = new View[operators.length];
// For efficiency, the outer loop should be CellLayout.
for (CellLayout cellLayout : cellLayouts) {
- mapOverCellLayout(MAP_NO_RECURSE, cellLayout, (info, v) -> {
+ mapOverCellLayout(cellLayout, (info, v) -> {
for (int i = 0; i < operators.length; ++i) {
if (matches[i] == null && operators[i].evaluate(info, v)) {
matches[i] = v;
@@ -3009,7 +3005,7 @@
}
void clearDropTargets() {
- mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
+ mapOverItems(new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View v) {
if (v instanceof DropTarget) {
@@ -3054,10 +3050,12 @@
} else if (itemToRemove.container >= 0) {
// The item may belong to a folder.
View parent = idToViewMap.get(itemToRemove.container);
- if (parent != null) {
+ if (parent instanceof FolderIcon) {
FolderInfo folderInfo = (FolderInfo) parent.getTag();
- folderInfo.prepareAutoUpdate();
folderInfo.remove((WorkspaceItemInfo) itemToRemove, false);
+ if (((FolderIcon) parent).getFolder().isOpen()) {
+ ((FolderIcon) parent).getFolder().close(false /* animate */);
+ }
}
}
}
@@ -3081,18 +3079,17 @@
/**
* Map the operator over the shortcuts and widgets, return the first-non-null value.
*
- * @param recurse true: iterate over folder children. false: op get the folders themselves.
* @param op the operator to map over the shortcuts
*/
- public void mapOverItems(boolean recurse, ItemOperator op) {
+ public void mapOverItems(ItemOperator op) {
for (CellLayout layout : getWorkspaceAndHotseatCellLayouts()) {
- if (mapOverCellLayout(recurse, layout, op)) {
+ if (mapOverCellLayout(layout, op)) {
return;
}
}
}
- private boolean mapOverCellLayout(boolean recurse, CellLayout layout, ItemOperator op) {
+ private boolean mapOverCellLayout(CellLayout layout, ItemOperator op) {
// TODO(b/128460496) Potential race condition where layout is not yet loaded
if (layout == null) {
return false;
@@ -3102,103 +3099,68 @@
final int itemCount = container.getChildCount();
for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) {
View item = container.getChildAt(itemIdx);
- ItemInfo info = (ItemInfo) item.getTag();
- if (recurse && info instanceof FolderInfo && item instanceof FolderIcon) {
- FolderIcon folder = (FolderIcon) item;
- ArrayList<View> folderChildren = folder.getFolder().getIconsInReadingOrder();
- // map over all the children in the folder
- final int childCount = folderChildren.size();
- for (int childIdx = 0; childIdx < childCount; childIdx++) {
- View child = folderChildren.get(childIdx);
- info = (ItemInfo) child.getTag();
- if (op.evaluate(info, child)) {
- return true;
- }
- }
- } else {
- if (op.evaluate(info, item)) {
- return true;
- }
+ if (op.evaluate((ItemInfo) item.getTag(), item)) {
+ return true;
}
}
return false;
}
void updateShortcuts(ArrayList<WorkspaceItemInfo> shortcuts) {
- int total = shortcuts.size();
- final HashSet<WorkspaceItemInfo> updates = new HashSet<>(total);
- final IntSet folderIds = new IntSet();
+ final HashSet<WorkspaceItemInfo> updates = new HashSet<>(shortcuts);
+ ItemOperator op = (info, v) -> {
+ if (v instanceof BubbleTextView && updates.contains(info)) {
+ WorkspaceItemInfo si = (WorkspaceItemInfo) info;
+ BubbleTextView shortcut = (BubbleTextView) v;
+ Drawable oldIcon = shortcut.getIcon();
+ boolean oldPromiseState = (oldIcon instanceof PreloadIconDrawable)
+ && ((PreloadIconDrawable) oldIcon).hasNotCompleted();
+ shortcut.applyFromWorkspaceItem(si, si.isPromise() != oldPromiseState);
+ } else if (info instanceof FolderInfo && v instanceof FolderIcon) {
+ ((FolderIcon) v).updatePreviewItems(updates::contains);
+ }
- for (int i = 0; i < total; i++) {
- WorkspaceItemInfo s = shortcuts.get(i);
- updates.add(s);
- folderIds.add(s.container);
+ // Iterate all items
+ return false;
+ };
+
+ mapOverItems(op);
+ Folder openFolder = Folder.getOpen(mLauncher);
+ if (openFolder != null) {
+ openFolder.iterateOverItems(op);
}
-
- mapOverItems(MAP_RECURSE, new ItemOperator() {
- @Override
- public boolean evaluate(ItemInfo info, View v) {
- if (info instanceof WorkspaceItemInfo && v instanceof BubbleTextView &&
- updates.contains(info)) {
- WorkspaceItemInfo si = (WorkspaceItemInfo) info;
- BubbleTextView shortcut = (BubbleTextView) v;
- Drawable oldIcon = shortcut.getIcon();
- boolean oldPromiseState = (oldIcon instanceof PreloadIconDrawable)
- && ((PreloadIconDrawable) oldIcon).hasNotCompleted();
- shortcut.applyFromWorkspaceItem(si, si.isPromise() != oldPromiseState);
- }
- // process all the shortcuts
- return false;
- }
- });
-
- // Update folder icons
- mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
- @Override
- public boolean evaluate(ItemInfo info, View v) {
- if (info instanceof FolderInfo && folderIds.contains(info.id)) {
- ((FolderInfo) info).itemsChanged(false);
- }
- // process all the shortcuts
- return false;
- }
- });
}
public void updateNotificationDots(Predicate<PackageUserKey> updatedDots) {
final PackageUserKey packageUserKey = new PackageUserKey(null, null);
- final IntSet folderIds = new IntSet();
- mapOverItems(MAP_RECURSE, new ItemOperator() {
- @Override
- public boolean evaluate(ItemInfo info, View v) {
- if (info instanceof WorkspaceItemInfo && v instanceof BubbleTextView) {
- if (!packageUserKey.updateFromItemInfo(info)
- || updatedDots.test(packageUserKey)) {
- ((BubbleTextView) v).applyDotState(info, true /* animate */);
- folderIds.add(info.container);
- }
- }
- // process all the shortcuts
- return false;
- }
- });
+ Predicate<ItemInfo> matcher = info -> !packageUserKey.updateFromItemInfo(info)
+ || updatedDots.test(packageUserKey);
- // Update folder icons
- mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
- @Override
- public boolean evaluate(ItemInfo info, View v) {
- if (info instanceof FolderInfo && folderIds.contains(info.id)
- && v instanceof FolderIcon) {
+ ItemOperator op = (info, v) -> {
+ if (info instanceof WorkspaceItemInfo && v instanceof BubbleTextView) {
+ if (matcher.test(info)) {
+ ((BubbleTextView) v).applyDotState(info, true /* animate */);
+ }
+ } else if (info instanceof FolderInfo && v instanceof FolderIcon) {
+ FolderInfo fi = (FolderInfo) info;
+ if (fi.contents.stream().anyMatch(matcher)) {
FolderDotInfo folderDotInfo = new FolderDotInfo();
- for (WorkspaceItemInfo si : ((FolderInfo) info).contents) {
+ for (WorkspaceItemInfo si : fi.contents) {
folderDotInfo.addDotInfo(mLauncher.getDotInfoForItem(si));
}
((FolderIcon) v).setDotInfo(folderDotInfo);
}
- // process all the shortcuts
- return false;
}
- });
+
+ // process all the shortcuts
+ return false;
+ };
+
+ mapOverItems(op);
+ Folder folder = Folder.getOpen(mLauncher);
+ if (folder != null) {
+ folder.iterateOverItems(op);
+ }
}
public void removeAbandonedPromise(String packageName, UserHandle user) {
@@ -3210,21 +3172,25 @@
}
public void updateRestoreItems(final HashSet<ItemInfo> updates) {
- mapOverItems(MAP_RECURSE, new ItemOperator() {
- @Override
- public boolean evaluate(ItemInfo info, View v) {
- if (info instanceof WorkspaceItemInfo && v instanceof BubbleTextView
- && updates.contains(info)) {
- ((BubbleTextView) v).applyPromiseState(false /* promiseStateChanged */);
- } else if (v instanceof PendingAppWidgetHostView
- && info instanceof LauncherAppWidgetInfo
- && updates.contains(info)) {
- ((PendingAppWidgetHostView) v).applyState();
- }
- // process all the shortcuts
- return false;
+ ItemOperator op = (info, v) -> {
+ if (info instanceof WorkspaceItemInfo && v instanceof BubbleTextView
+ && updates.contains(info)) {
+ ((BubbleTextView) v).applyPromiseState(false /* promiseStateChanged */);
+ } else if (v instanceof PendingAppWidgetHostView
+ && info instanceof LauncherAppWidgetInfo
+ && updates.contains(info)) {
+ ((PendingAppWidgetHostView) v).applyState();
+ } else if (v instanceof FolderIcon && info instanceof FolderInfo) {
+ ((FolderIcon) v).updatePreviewItems(updates::contains);
}
- });
+ // process all the shortcuts
+ return false;
+ };
+ mapOverItems(op);
+ Folder folder = Folder.getOpen(mLauncher);
+ if (folder != null) {
+ folder.iterateOverItems(op);
+ }
}
public void widgetsRestored(final ArrayList<LauncherAppWidgetInfo> changedInfo) {
@@ -3248,7 +3214,7 @@
} else {
// widgetRefresh will automatically run when the packages are updated.
// For now just update the progress bars
- mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
+ mapOverItems(new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View view) {
if (view instanceof PendingAppWidgetHostView
@@ -3372,7 +3338,7 @@
mRefreshPending = false;
ArrayList<PendingAppWidgetHostView> views = new ArrayList<>(mInfos.size());
- mapOverItems(MAP_NO_RECURSE, (info, view) -> {
+ mapOverItems((info, view) -> {
if (view instanceof PendingAppWidgetHostView && mInfos.contains(info)) {
views.add((PendingAppWidgetHostView) view);
}
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 1399302..f82e380 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -34,6 +34,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
+import com.android.launcher3.allapps.AllAppsGridAdapter.AppsGridLayoutManager;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -113,6 +114,13 @@
if (mScrollbar != null) {
mScrollbar.reattachThumbToScroll();
}
+ if (getLayoutManager() instanceof AppsGridLayoutManager) {
+ AppsGridLayoutManager layoutManager = (AppsGridLayoutManager) getLayoutManager();
+ if (layoutManager.findFirstCompletelyVisibleItemPosition() == 0) {
+ // We are at the top, so don't scrollToPosition (would cause unnecessary relayout).
+ return;
+ }
+ }
scrollToPosition(0);
}
@@ -419,13 +427,4 @@
public boolean hasOverlappingRendering() {
return false;
}
-
- @Override
- public void onScrollStateChanged(int state) {
- super.onScrollStateChanged(state);
-
- if (state == SCROLL_STATE_IDLE) {
- AccessibilityManagerCompat.sendScrollFinishedEventToTest(getContext());
- }
- }
}
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index dfddc61..3836c9f 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -1,7 +1,5 @@
package com.android.launcher3.allapps;
-import static android.view.View.ALPHA;
-
import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT;
import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
@@ -12,7 +10,6 @@
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_HEADER_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS;
-import static com.android.launcher3.anim.AnimatorSetBuilder.FLAG_DONT_UPDATE_ALL_APPS_VISIBILITY;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
@@ -21,7 +18,6 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.util.FloatProperty;
-import android.view.View;
import android.view.animation.Interpolator;
import com.android.launcher3.DeviceProfile;
@@ -215,12 +211,7 @@
Interpolator allAppsFade = builder.getInterpolator(ANIM_ALL_APPS_FADE, LINEAR);
Interpolator headerFade = builder.getInterpolator(ANIM_ALL_APPS_HEADER_FADE, allAppsFade);
- View allAppsContent = mAppsView.getContentView();
- if (!hasAllAppsContent && builder.hasFlag(FLAG_DONT_UPDATE_ALL_APPS_VISIBILITY)) {
- setter.setFloat(allAppsContent, ALPHA, 0, allAppsFade);
- } else {
- setter.setViewAlpha(allAppsContent, hasAllAppsContent ? 1 : 0, allAppsFade);
- }
+ setter.setViewAlpha(mAppsView.getContentView(), hasAllAppsContent ? 1 : 0, allAppsFade);
setter.setViewAlpha(mAppsView.getScrollBar(), hasAllAppsContent ? 1 : 0, allAppsFade);
mAppsView.getFloatingHeaderView().setContentVisibility(hasHeaderExtra, hasAllAppsContent,
setter, headerFade, allAppsFade);
diff --git a/src/com/android/launcher3/anim/AnimatorSetBuilder.java b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
index 07e7553..cd30dea 100644
--- a/src/com/android/launcher3/anim/AnimatorSetBuilder.java
+++ b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
@@ -43,7 +43,6 @@
public static final int ANIM_ALL_APPS_HEADER_FADE = 12; // e.g. predictions
public static final int FLAG_DONT_ANIMATE_OVERVIEW = 1 << 0;
- public static final int FLAG_DONT_UPDATE_ALL_APPS_VISIBILITY = 1 << 1;
protected final ArrayList<Animator> mAnims = new ArrayList<>();
diff --git a/src/com/android/launcher3/dragndrop/DragDriver.java b/src/com/android/launcher3/dragndrop/DragDriver.java
index bd2a03b..01e0f92 100644
--- a/src/com/android/launcher3/dragndrop/DragDriver.java
+++ b/src/com/android/launcher3/dragndrop/DragDriver.java
@@ -61,6 +61,9 @@
mEventListener.onDriverDragEnd(ev.getX(), ev.getY());
break;
case MotionEvent.ACTION_CANCEL:
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_DRAG_TO_WORKSPACE, "DragDriver.ACTION_CANCEL");
+ }
mEventListener.onDriverDragCancel();
break;
}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 28c25cf..65d593c 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -170,8 +170,6 @@
private boolean mDeleteFolderOnDropCompleted = false;
private boolean mSuppressFolderDeletion = false;
private boolean mItemAddedBackToSelfViaIcon = false;
- @Thunk float mFolderIconPivotX;
- @Thunk float mFolderIconPivotY;
private boolean mIsEditingName = false;
@ViewDebug.ExportedProperty(category = "launcher")
@@ -310,7 +308,8 @@
// Convert to a string here to ensure that no other state associated with the text field
// gets saved.
String newTitle = mFolderName.getText().toString();
- mInfo.setTitle(newTitle);
+ mInfo.title = newTitle;
+ mFolderIcon.onTitleChanged(newTitle);
mLauncher.getModelWriter().updateItemInDatabase(mInfo);
if (TextUtils.isEmpty(mInfo.title)) {
@@ -385,7 +384,6 @@
ArrayList<WorkspaceItemInfo> children = info.contents;
Collections.sort(children, ITEM_POS_COMPARATOR);
updateItemLocationsInDatabaseBatch();
- mContent.bindItems(children);
DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
if (lp == null) {
@@ -393,13 +391,10 @@
lp.customPosition = true;
setLayoutParams(lp);
}
- centerAboutIcon();
-
mItemsInvalidated = true;
- updateTextViewFocus();
mInfo.addListener(this);
- if (TextUtils.isEmpty(mInfo.title)) {
+ if (!TextUtils.isEmpty(mInfo.title)) {
mFolderName.setText(mInfo.title);
mFolderName.setHint(null);
} else {
@@ -408,11 +403,9 @@
}
// In case any children didn't come across during loading, clean up the folder accordingly
- mFolderIcon.post(new Runnable() {
- public void run() {
- if (getItemCount() <= 1) {
- replaceFolderWithFinalItem();
- }
+ mFolderIcon.post(() -> {
+ if (getItemCount() <= 1) {
+ replaceFolderWithFinalItem();
}
});
}
@@ -473,17 +466,49 @@
}
/**
+ * Opens the folder as part of a drag operation
+ */
+ public void beginExternalDrag() {
+ mIsExternalDrag = true;
+ mDragInProgress = true;
+
+ // Since this folder opened by another controller, it might not get onDrop or
+ // onDropComplete. Perform cleanup once drag-n-drop ends.
+ mDragController.addDragListener(this);
+
+ ArrayList<WorkspaceItemInfo> items = new ArrayList<>(mInfo.contents);
+ mEmptyCellRank = items.size();
+ items.add(null); // Add an empty spot at the end
+
+ animateOpen(items, mEmptyCellRank / mContent.itemsPerPage());
+ }
+
+ /**
* Opens the user folder described by the specified tag. The opening of the folder
* is animated relative to the specified View. If the View is null, no animation
* is played.
*/
public void animateOpen() {
+ animateOpen(mInfo.contents, 0);
+ }
+
+ /**
+ * Opens the user folder described by the specified tag. The opening of the folder
+ * is animated relative to the specified View. If the View is null, no animation
+ * is played.
+ */
+ private void animateOpen(List<WorkspaceItemInfo> items, int pageNo) {
Folder openFolder = getOpen(mLauncher);
if (openFolder != null && openFolder != this) {
// Close any open folder before opening a folder.
openFolder.close(true);
}
+ mContent.bindItems(items);
+ centerAboutIcon();
+ mItemsInvalidated = true;
+ updateTextViewFocus();
+
mIsOpen = true;
DragLayer dragLayer = mLauncher.getDragLayer();
@@ -500,10 +525,7 @@
}
mContent.completePendingPageChanges();
- if (!mDragInProgress) {
- // Open on the first page.
- mContent.snapToPageImmediately(0);
- }
+ mContent.snapToPageImmediately(pageNo);
// This is set to true in close(), but isn't reset to false until onDropCompleted(). This
// leads to an inconsistent state if you drag out of the folder and drag back in without
@@ -516,7 +538,7 @@
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
- mFolderIcon.setBackgroundVisible(false);
+ mFolderIcon.setIconVisible(false);
mFolderIcon.drawLeaveBehindIfExists();
}
@Override
@@ -574,16 +596,6 @@
mContent.verifyVisibleHighResIcons(mContent.getNextPage());
}
- public void beginExternalDrag() {
- mEmptyCellRank = mContent.allocateRankForNewItem();
- mIsExternalDrag = true;
- mDragInProgress = true;
-
- // Since this folder opened by another controller, it might not get onDrop or
- // onDropComplete. Perform cleanup once drag-n-drop ends.
- mDragController.addDragListener(this);
- }
-
@Override
protected boolean isOfType(int type) {
return (type & TYPE_FOLDER) != 0;
@@ -646,7 +658,7 @@
clearFocus();
if (mFolderIcon != null) {
mFolderIcon.setVisibility(View.VISIBLE);
- mFolderIcon.setBackgroundVisible(true);
+ mFolderIcon.setIconVisible(true);
mFolderIcon.mFolderName.setTextVisibility(true);
if (wasAnimated) {
mFolderIcon.animateBgShadowAndStroke();
@@ -668,6 +680,8 @@
} else if (mDragInProgress) {
mDeleteFolderOnDropCompleted = true;
}
+ } else if (!mDragInProgress) {
+ mContent.unbindItems();
}
mSuppressFolderDeletion = false;
clearDragInfo();
@@ -953,24 +967,12 @@
setPivotX(folderPivotX);
setPivotY(folderPivotY);
- mFolderIconPivotX = (int) (mFolderIcon.getMeasuredWidth() *
- (1.0f * folderPivotX / width));
- mFolderIconPivotY = (int) (mFolderIcon.getMeasuredHeight() *
- (1.0f * folderPivotY / height));
-
lp.width = width;
lp.height = height;
lp.x = left;
lp.y = top;
}
- public float getPivotXForIconAnimation() {
- return mFolderIconPivotX;
- }
- public float getPivotYForIconAnimation() {
- return mFolderIconPivotY;
- }
-
private int getContentAreaHeight() {
DeviceProfile grid = mLauncher.getDeviceProfile();
int maxContentAreaHeight = grid.availableHeightPx
@@ -1031,7 +1033,7 @@
}
public int getItemCount() {
- return mContent.getItemCount();
+ return mInfo.contents.size();
}
@Thunk void replaceFolderWithFinalItem() {
@@ -1039,7 +1041,7 @@
Runnable onCompleteRunnable = new Runnable() {
@Override
public void run() {
- int itemCount = mInfo.contents.size();
+ int itemCount = getItemCount();
if (itemCount <= 1) {
View newIcon = null;
@@ -1116,6 +1118,8 @@
return false;
}
});
+ } else {
+ setOnKeyListener(null);
}
}
@@ -1242,9 +1246,9 @@
item.cellY);
updateItemLocationsInDatabaseBatch();
- ArrayList<View> items = new ArrayList<>(getIconsInReadingOrder());
- items.add(rank, mContent.createAndAddViewForRank(item, rank));
- mContent.arrangeChildren(items);
+ if (mContent.areViewsBound()) {
+ mContent.createAndAddViewForRank(item, rank);
+ }
mItemsInvalidated = true;
}
@@ -1275,12 +1279,11 @@
updateTextViewFocus();
}
- @Override
- public void prepareAutoUpdate() {
- close(false);
- }
-
- public void onTitleChanged(CharSequence title) {
+ /**
+ * Utility methods to iterate over items of the view
+ */
+ public void iterateOverItems(ItemOperator op) {
+ mContent.iterateOverItems(op);
}
/**
@@ -1289,14 +1292,7 @@
public ArrayList<View> getIconsInReadingOrder() {
if (mItemsInvalidated) {
mItemsInReadingOrder.clear();
- mContent.iterateOverItems(new ItemOperator() {
-
- @Override
- public boolean evaluate(ItemInfo info, View view) {
- mItemsInReadingOrder.add(view);
- return false;
- }
- });
+ mContent.iterateOverItems((i, v) -> !mItemsInReadingOrder.add(v));
mItemsInvalidated = false;
}
return mItemsInReadingOrder;
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 686684d..a463c7a 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -65,15 +65,17 @@
import com.android.launcher3.icons.DotRenderer;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.util.Thunk;
+import com.android.launcher3.views.IconLabelDotView;
import com.android.launcher3.widget.PendingAddShortcutInfo;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Predicate;
/**
* An icon that can appear on in the workspace representing an {@link Folder}.
*/
-public class FolderIcon extends FrameLayout implements FolderListener {
+public class FolderIcon extends FrameLayout implements FolderListener, IconLabelDotView {
@Thunk Launcher mLauncher;
@Thunk Folder mFolder;
@@ -99,7 +101,7 @@
ClippedFolderIconLayoutRule mPreviewLayoutRule;
private PreviewItemManager mPreviewItemManager;
private PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0);
- private List<BubbleTextView> mCurrentPreviewItems = new ArrayList<>();
+ private List<WorkspaceItemInfo> mCurrentPreviewItems = new ArrayList<>();
boolean mAnimating = false;
@@ -107,6 +109,7 @@
private Alarm mOpenAlarm = new Alarm();
+ private boolean mForceHideDot;
@ViewDebug.ExportedProperty(category = "launcher", deepExport = true)
private FolderDotInfo mDotInfo = new FolderDotInfo();
private DotRenderer mDotRenderer;
@@ -255,7 +258,6 @@
OnAlarmListener mOnOpenListener = new OnAlarmListener() {
public void onAlarm(Alarm alarm) {
mFolder.beginExternalDrag();
- mFolder.animateOpen();
}
};
@@ -321,18 +323,17 @@
int numItemsInPreview = Math.min(MAX_NUM_ITEMS_IN_PREVIEW, index + 1);
boolean itemAdded = false;
if (itemReturnedOnFailedDrop || index >= MAX_NUM_ITEMS_IN_PREVIEW) {
- List<BubbleTextView> oldPreviewItems = new ArrayList<>(mCurrentPreviewItems);
+ List<WorkspaceItemInfo> oldPreviewItems = new ArrayList<>(mCurrentPreviewItems);
mInfo.add(item, index, false);
mCurrentPreviewItems.clear();
- mCurrentPreviewItems.addAll(getPreviewIconsOnPage(0));
+ mCurrentPreviewItems.addAll(getPreviewItemsOnPage(0));
if (!oldPreviewItems.equals(mCurrentPreviewItems)) {
- for (int i = 0; i < mCurrentPreviewItems.size(); ++i) {
- if (mCurrentPreviewItems.get(i).getTag().equals(item)) {
- // If the item dropped is going to be in the preview, we update the
- // index here to reflect its position in the preview.
- index = i;
- }
+ int newIndex = mCurrentPreviewItems.indexOf(item);
+ if (newIndex >= 0) {
+ // If the item dropped is going to be in the preview, we update the
+ // index here to reflect its position in the preview.
+ index = newIndex;
}
mPreviewItemManager.hidePreviewItem(index, true);
@@ -405,6 +406,20 @@
return mPreviewLayoutRule;
}
+ @Override
+ public void setForceHideDot(boolean forceHideDot) {
+ if (mForceHideDot == forceHideDot) {
+ return;
+ }
+ mForceHideDot = forceHideDot;
+
+ if (forceHideDot) {
+ invalidate();
+ } else if (hasDot()) {
+ animateDotScale(0, 1);
+ }
+ }
+
/**
* Sets mDotScale to 1 or 0, animating if wasDotted or isDotted is false
* (the dot is being added or removed).
@@ -464,7 +479,8 @@
mBackground.setInvalidateDelegate(this);
}
- public void setBackgroundVisible(boolean visible) {
+ @Override
+ public void setIconVisible(boolean visible) {
mBackgroundIsVisible = visible;
invalidate();
}
@@ -504,7 +520,7 @@
}
public void drawDot(Canvas canvas) {
- if ((mDotInfo != null && mDotInfo.hasDot()) || mDotScale > 0) {
+ if (!mForceHideDot && ((mDotInfo != null && mDotInfo.hasDot()) || mDotScale > 0)) {
Rect iconBounds = mDotParams.iconBounds;
BubbleTextView.getIconBounds(this, iconBounds,
mLauncher.getWallpaperDeviceProfile().iconSizePx);
@@ -531,11 +547,10 @@
}
/**
- * Returns the list of "preview items" on {@param page}.
+ * Returns the list of items which should be visible in the preview
*/
- public List<BubbleTextView> getPreviewIconsOnPage(int page) {
- return mPreviewVerifier.setFolderInfo(mFolder.mInfo)
- .previewItemsForPage(page, mFolder.getIconsInReadingOrder());
+ public List<WorkspaceItemInfo> getPreviewItemsOnPage(int page) {
+ return mPreviewVerifier.setFolderInfo(mInfo).previewItemsForPage(page, mInfo.contents);
}
@Override
@@ -553,11 +568,14 @@
private void updatePreviewItems(boolean animate) {
mPreviewItemManager.updatePreviewItems(animate);
mCurrentPreviewItems.clear();
- mCurrentPreviewItems.addAll(getPreviewIconsOnPage(0));
+ mCurrentPreviewItems.addAll(getPreviewItemsOnPage(0));
}
- @Override
- public void prepareAutoUpdate() {
+ /**
+ * Updates the preview items which match the provided condition
+ */
+ public void updatePreviewItems(Predicate<WorkspaceItemInfo> itemCheck) {
+ mPreviewItemManager.updatePreviewItems(itemCheck);
}
@Override
@@ -580,7 +598,6 @@
requestLayout();
}
- @Override
public void onTitleChanged(CharSequence title) {
mFolderName.setText(title);
setContentDescription(getContext().getString(R.string.folder_name_format, title));
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index 3e00cae..54b363e 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -24,10 +24,10 @@
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
-import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewDebug;
+import com.android.launcher3.BaseActivity;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DeviceProfile;
@@ -46,11 +46,14 @@
import com.android.launcher3.pageindicators.PageIndicatorDots;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.util.Thunk;
+import com.android.launcher3.util.ViewCache;
import java.util.ArrayList;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.function.ToIntFunction;
+import java.util.stream.Collectors;
public class FolderPagedView extends PagedView<PageIndicatorDots> {
@@ -69,12 +72,12 @@
public final boolean mIsRtl;
- private final LayoutInflater mInflater;
private final ViewGroupFocusHelper mFocusIndicatorHelper;
@Thunk final ArrayMap<View, Runnable> mPendingAnimations = new ArrayMap<>();
private final FolderGridOrganizer mOrganizer;
+ private final ViewCache mViewCache;
private int mAllocatedContentSize;
@ViewDebug.ExportedProperty(category = "launcher")
@@ -84,17 +87,20 @@
private Folder mFolder;
+ // If the views are attached to the folder or not. A folder should be bound when its
+ // animating or is open.
+ private boolean mViewsBound = false;
+
public FolderPagedView(Context context, AttributeSet attrs) {
super(context, attrs);
InvariantDeviceProfile profile = LauncherAppState.getIDP(context);
mOrganizer = new FolderGridOrganizer(profile);
- mInflater = LayoutInflater.from(context);
-
mIsRtl = Utilities.isRtl(getResources());
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
mFocusIndicatorHelper = new ViewGroupFocusHelper(this);
+ mViewCache = BaseActivity.fromContext(context).getViewCache();
}
public void setFolder(Folder folder) {
@@ -127,35 +133,50 @@
/**
* Binds items to the layout.
*/
- public void bindItems(ArrayList<WorkspaceItemInfo> items) {
- ArrayList<View> icons = new ArrayList<>();
- for (WorkspaceItemInfo item : items) {
- icons.add(createNewView(item));
+ public void bindItems(List<WorkspaceItemInfo> items) {
+ if (mViewsBound) {
+ unbindItems();
}
- arrangeChildren(icons);
- }
-
- public void allocateSpaceForRank(int rank) {
- ArrayList<View> views = new ArrayList<>(mFolder.getIconsInReadingOrder());
- views.add(rank, null);
- arrangeChildren(views);
+ arrangeChildren(items.stream().map(this::createNewView).collect(Collectors.toList()));
+ mViewsBound = true;
}
/**
- * Create space for a new item at the end, and returns the rank for that item.
- * Also sets the current page to the last page.
+ * Removes all the icons from the folder
*/
- public int allocateRankForNewItem() {
- int rank = getItemCount();
- allocateSpaceForRank(rank);
- setCurrentPage(rank / mOrganizer.getMaxItemsPerPage());
- return rank;
+ public void unbindItems() {
+ for (int i = getChildCount() - 1; i >= 0; i--) {
+ CellLayout page = (CellLayout) getChildAt(i);
+ ShortcutAndWidgetContainer container = page.getShortcutsAndWidgets();
+ for (int j = container.getChildCount() - 1; j >= 0; j--) {
+ mViewCache.recycleView(R.layout.folder_application, container.getChildAt(j));
+ }
+ page.removeAllViews();
+ mViewCache.recycleView(R.layout.folder_page, page);
+ }
+ removeAllViews();
+ mViewsBound = false;
}
+ /**
+ * Returns true if the icons are bound to the folder
+ */
+ public boolean areViewsBound() {
+ return mViewsBound;
+ }
+
+ /**
+ * Creates and adds an icon corresponding to the provided rank
+ * @return the created icon
+ */
public View createAndAddViewForRank(WorkspaceItemInfo item, int rank) {
View icon = createNewView(item);
- allocateSpaceForRank(rank);
- addViewForRank(icon, item, rank);
+ if (!mViewsBound) {
+ return icon;
+ }
+ ArrayList<View> views = new ArrayList<>(mFolder.getIconsInReadingOrder());
+ views.add(rank, icon);
+ arrangeChildren(views);
return icon;
}
@@ -173,16 +194,24 @@
@SuppressLint("InflateParams")
public View createNewView(WorkspaceItemInfo item) {
- final BubbleTextView textView = (BubbleTextView) mInflater.inflate(
- R.layout.folder_application, null, false);
+ if (item == null) {
+ return null;
+ }
+ final BubbleTextView textView = mViewCache.getView(
+ R.layout.folder_application, getContext(), null);
textView.applyFromWorkspaceItem(item);
- textView.setHapticFeedbackEnabled(false);
textView.setOnClickListener(ItemClickHandler.INSTANCE);
textView.setOnLongClickListener(mFolder);
textView.setOnFocusChangeListener(mFocusIndicatorHelper);
-
- textView.setLayoutParams(new CellLayout.LayoutParams(
- item.cellX, item.cellY, item.spanX, item.spanY));
+ CellLayout.LayoutParams lp = (CellLayout.LayoutParams) textView.getLayoutParams();
+ if (lp == null) {
+ textView.setLayoutParams(new CellLayout.LayoutParams(
+ item.cellX, item.cellY, item.spanX, item.spanY));
+ } else {
+ lp.cellX = item.cellX;
+ lp.cellY = item.cellY;
+ lp.cellHSpan = lp.cellVSpan = 1;
+ }
return textView;
}
@@ -197,7 +226,7 @@
private CellLayout createAndAddNewPage() {
DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
- CellLayout page = (CellLayout) mInflater.inflate(R.layout.folder_page, this, false);
+ CellLayout page = mViewCache.getView(R.layout.folder_page, getContext(), this);
page.setCellDimensions(grid.folderCellWidthPx, grid.folderCellHeightPx);
page.getShortcutsAndWidgets().setMotionEventSplittingEnabled(false);
page.setInvertIfRtl(true);
@@ -240,7 +269,7 @@
* @param list the ordered list of children.
*/
@SuppressLint("RtlHardcoded")
- public void arrangeChildren(ArrayList<View> list) {
+ public void arrangeChildren(List<View> list) {
int itemCount = list.size();
ArrayList<CellLayout> pages = new ArrayList<>();
for (int i = 0; i < getChildCount(); i++) {
@@ -313,16 +342,6 @@
(getPageAt(0).getDesiredHeight() + getPaddingTop() + getPaddingBottom()) : 0;
}
- public int getItemCount() {
- int lastPageIndex = getChildCount() - 1;
- if (lastPageIndex < 0) {
- // If there are no pages, nothing has yet been added to the folder.
- return 0;
- }
- return getPageAt(lastPageIndex).getShortcutsAndWidgets().getChildCount()
- + lastPageIndex * mOrganizer.getMaxItemsPerPage();
- }
-
/**
* @return the rank of the cell nearest to the provided pixel position.
*/
diff --git a/src/com/android/launcher3/folder/PreviewItemDrawingParams.java b/src/com/android/launcher3/folder/PreviewItemDrawingParams.java
index c818462..caf6e55 100644
--- a/src/com/android/launcher3/folder/PreviewItemDrawingParams.java
+++ b/src/com/android/launcher3/folder/PreviewItemDrawingParams.java
@@ -17,6 +17,8 @@
import android.graphics.drawable.Drawable;
+import com.android.launcher3.WorkspaceItemInfo;
+
/**
* Manages the parameters used to draw a Folder preview item.
*/
@@ -25,9 +27,10 @@
float transY;
float scale;
float overlayAlpha;
- FolderPreviewItemAnim anim;
+ public FolderPreviewItemAnim anim;
public boolean hidden;
- Drawable drawable;
+ public Drawable drawable;
+ public WorkspaceItemInfo item;
PreviewItemDrawingParams(float transX, float transY, float scale, float overlayAlpha) {
this.transX = transX;
diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java
index 2ac6bf4..2d817e6 100644
--- a/src/com/android/launcher3/folder/PreviewItemManager.java
+++ b/src/com/android/launcher3/folder/PreviewItemManager.java
@@ -23,28 +23,51 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
+import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.util.FloatProperty;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
-import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.Launcher;
import com.android.launcher3.Utilities;
import com.android.launcher3.WorkspaceItemInfo;
+import com.android.launcher3.graphics.DrawableFactory;
+import com.android.launcher3.graphics.PreloadIconDrawable;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Predicate;
/**
* Manages the drawing and animations of {@link PreviewItemDrawingParams} for a {@link FolderIcon}.
*/
public class PreviewItemManager {
- private FolderIcon mIcon;
+ private static final FloatProperty<PreviewItemManager> CURRENT_PAGE_ITEMS_TRANS_X =
+ new FloatProperty<PreviewItemManager>("currentPageItemsTransX") {
+ @Override
+ public void setValue(PreviewItemManager manager, float v) {
+ manager.mCurrentPageItemsTransX = v;
+ manager.onParamsChanged();
+ }
+
+ @Override
+ public Float get(PreviewItemManager manager) {
+ return manager.mCurrentPageItemsTransX;
+ }
+ };
+
+ private final Context mContext;
+ private final FolderIcon mIcon;
+ private final DrawableFactory mDrawableFactory;
+ private final int mIconSize;
// These variables are all associated with the drawing of the preview; they are stored
// as member variables for shared usage and to avoid computation on each frame
@@ -69,7 +92,10 @@
private static final int ITEM_SLIDE_IN_OUT_DISTANCE_PX = 200;
public PreviewItemManager(FolderIcon icon) {
+ mContext = icon.getContext();
mIcon = icon;
+ mDrawableFactory = DrawableFactory.INSTANCE.get(mContext);
+ mIconSize = Launcher.getLauncher(mContext).getDeviceProfile().folderChildIconSizePx;
}
/**
@@ -200,7 +226,7 @@
}
void buildParamsForPage(int page, ArrayList<PreviewItemDrawingParams> params, boolean animate) {
- List<BubbleTextView> items = mIcon.getPreviewIconsOnPage(page);
+ List<WorkspaceItemInfo> items = mIcon.getPreviewItemsOnPage(page);
int prevNumItems = params.size();
// We adjust the size of the list to match the number of items in the preview.
@@ -214,13 +240,7 @@
int numItemsInFirstPagePreview = page == 0 ? items.size() : MAX_NUM_ITEMS_IN_PREVIEW;
for (int i = 0; i < params.size(); i++) {
PreviewItemDrawingParams p = params.get(i);
- p.drawable = items.get(i).getCompoundDrawables()[1];
-
- if (p.drawable != null && !mIcon.mFolder.isOpen()) {
- // Set the callback to FolderIcon as it is responsible to drawing the icon. The
- // callback will be released when the folder is opened.
- p.drawable.setCallback(mIcon);
- }
+ setDrawable(p, items.get(i));
if (!animate) {
computePreviewItemDrawingParams(i, numItemsInFirstPagePreview, p);
@@ -253,14 +273,8 @@
buildParamsForPage(currentPage, mCurrentPageParams, false);
onParamsChanged();
- ValueAnimator slideAnimator = ValueAnimator.ofFloat(0, ITEM_SLIDE_IN_OUT_DISTANCE_PX);
- slideAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator valueAnimator) {
- mCurrentPageItemsTransX = (float) valueAnimator.getAnimatedValue();
- onParamsChanged();
- }
- });
+ ValueAnimator slideAnimator = ObjectAnimator
+ .ofFloat(this, CURRENT_PAGE_ITEMS_TRANS_X, 0, ITEM_SLIDE_IN_OUT_DISTANCE_PX);
slideAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -277,6 +291,25 @@
buildParamsForPage(0, mFirstPageParams, animate);
}
+ void updatePreviewItems(Predicate<WorkspaceItemInfo> itemCheck) {
+ boolean modified = false;
+ for (PreviewItemDrawingParams param : mFirstPageParams) {
+ if (itemCheck.test(param.item)) {
+ setDrawable(param, param.item);
+ modified = true;
+ }
+ }
+ for (PreviewItemDrawingParams param : mCurrentPageParams) {
+ if (itemCheck.test(param.item)) {
+ setDrawable(param, param.item);
+ modified = true;
+ }
+ }
+ if (modified) {
+ mIcon.invalidate();
+ }
+ }
+
boolean verifyDrawable(@NonNull Drawable who) {
for (int i = 0; i < mFirstPageParams.size(); i++) {
if (mFirstPageParams.get(i).drawable == who) {
@@ -296,46 +329,46 @@
* - Moving into a new position
* - Moving out of the preview
*
- * @param oldParams The list of items in the old preview.
- * @param newParams The list of items in the new preview.
+ * @param oldItems The list of items in the old preview.
+ * @param newItems The list of items in the new preview.
* @param dropped The item that was dropped onto the FolderIcon.
*/
- public void onDrop(List<BubbleTextView> oldParams, List<BubbleTextView> newParams,
+ public void onDrop(List<WorkspaceItemInfo> oldItems, List<WorkspaceItemInfo> newItems,
WorkspaceItemInfo dropped) {
- int numItems = newParams.size();
+ int numItems = newItems.size();
final ArrayList<PreviewItemDrawingParams> params = mFirstPageParams;
buildParamsForPage(0, params, false);
// New preview items for items that are moving in (except for the dropped item).
- List<BubbleTextView> moveIn = new ArrayList<>();
- for (BubbleTextView btv : newParams) {
- if (!oldParams.contains(btv) && !btv.getTag().equals(dropped)) {
- moveIn.add(btv);
+ List<WorkspaceItemInfo> moveIn = new ArrayList<>();
+ for (WorkspaceItemInfo newItem : newItems) {
+ if (!oldItems.contains(newItem) && !newItem.equals(dropped)) {
+ moveIn.add(newItem);
}
}
for (int i = 0; i < moveIn.size(); ++i) {
- int prevIndex = newParams.indexOf(moveIn.get(i));
+ int prevIndex = newItems.indexOf(moveIn.get(i));
PreviewItemDrawingParams p = params.get(prevIndex);
computePreviewItemDrawingParams(prevIndex, numItems, p);
- updateTransitionParam(p, moveIn.get(i), ENTER_INDEX, newParams.indexOf(moveIn.get(i)),
+ updateTransitionParam(p, moveIn.get(i), ENTER_INDEX, newItems.indexOf(moveIn.get(i)),
numItems);
}
// Items that are moving into new positions within the preview.
- for (int newIndex = 0; newIndex < newParams.size(); ++newIndex) {
- int oldIndex = oldParams.indexOf(newParams.get(newIndex));
+ for (int newIndex = 0; newIndex < newItems.size(); ++newIndex) {
+ int oldIndex = oldItems.indexOf(newItems.get(newIndex));
if (oldIndex >= 0 && newIndex != oldIndex) {
PreviewItemDrawingParams p = params.get(newIndex);
- updateTransitionParam(p, newParams.get(newIndex), oldIndex, newIndex, numItems);
+ updateTransitionParam(p, newItems.get(newIndex), oldIndex, newIndex, numItems);
}
}
// Old preview items that need to be moved out.
- List<BubbleTextView> moveOut = new ArrayList<>(oldParams);
- moveOut.removeAll(newParams);
+ List<WorkspaceItemInfo> moveOut = new ArrayList<>(oldItems);
+ moveOut.removeAll(newItems);
for (int i = 0; i < moveOut.size(); ++i) {
- BubbleTextView item = moveOut.get(i);
- int oldIndex = oldParams.indexOf(item);
+ WorkspaceItemInfo item = moveOut.get(i);
+ int oldIndex = oldItems.indexOf(item);
PreviewItemDrawingParams p = computePreviewItemDrawingParams(oldIndex, numItems, null);
updateTransitionParam(p, item, oldIndex, EXIT_INDEX, numItems);
params.add(0, p); // We want these items first so that they are on drawn last.
@@ -348,14 +381,9 @@
}
}
- private void updateTransitionParam(final PreviewItemDrawingParams p, BubbleTextView btv,
+ private void updateTransitionParam(final PreviewItemDrawingParams p, WorkspaceItemInfo item,
int prevIndex, int newIndex, int numItems) {
- p.drawable = btv.getCompoundDrawables()[1];
- if (!mIcon.mFolder.isOpen()) {
- // Set the callback to FolderIcon as it is responsible to drawing the icon. The
- // callback will be released when the folder is opened.
- p.drawable.setCallback(mIcon);
- }
+ setDrawable(p, item);
FolderPreviewItemAnim anim = new FolderPreviewItemAnim(this, p, prevIndex, numItems,
newIndex, numItems, DROP_IN_ANIMATION_DURATION, null);
@@ -364,4 +392,20 @@
}
p.anim = anim;
}
+
+ private void setDrawable(PreviewItemDrawingParams p, WorkspaceItemInfo item) {
+ if (item.hasPromiseIconUi()) {
+ PreloadIconDrawable drawable = mDrawableFactory.newPendingIcon(mContext, item);
+ drawable.setLevel(item.getInstallProgress());
+ p.drawable = drawable;
+ } else {
+ p.drawable = mDrawableFactory.newIcon(mContext, item);
+ }
+ p.drawable.setBounds(0, 0, mIconSize, mIconSize);
+ p.item = item;
+
+ // Set the callback to FolderIcon as it is responsible to drawing the icon. The
+ // callback will be released when the folder is opened.
+ p.drawable.setCallback(mIcon);
+ }
}
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 2a40d68..c2aabca 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -300,7 +300,7 @@
}
mLauncher.getDragController().addDragListener(this);
- mOriginalIcon.forceHideDot(true);
+ mOriginalIcon.setForceHideDot(true);
// All views are added. Animate layout from now on.
setLayoutTransition(new LayoutTransition());
@@ -562,13 +562,13 @@
protected void onCreateCloseAnimation(AnimatorSet anim) {
// Animate original icon's text back in.
anim.play(mOriginalIcon.createTextAlphaAnimator(true /* fadeIn */));
- mOriginalIcon.forceHideDot(false);
+ mOriginalIcon.setForceHideDot(false);
}
@Override
protected void closeComplete() {
mOriginalIcon.setTextVisibility(mOriginalIcon.shouldTextBeVisible());
- mOriginalIcon.forceHideDot(false);
+ mOriginalIcon.setForceHideDot(false);
super.closeComplete();
}
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 516c251..de9d4a6 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.os.Bundle;
+import android.os.Debug;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
@@ -114,13 +115,13 @@
break;
}
- case TestProtocol.REQUEST_ALLOCATED_MEMORY: {
- final Runtime runtime = Runtime.getRuntime();
- response.putLong(TestProtocol.TEST_INFO_RESPONSE_FIELD,
- runtime.totalMemory() - runtime.freeMemory());
+ case TestProtocol.REQUEST_TOTAL_PSS_KB: {
+ Debug.MemoryInfo mem = new Debug.MemoryInfo();
+ Debug.getMemoryInfo(mem);
+ response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, mem.getTotalPss());
break;
}
}
return response;
}
-}
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index d569d40..60a59dd 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -73,7 +73,7 @@
public static final String REQUEST_APP_LIST_FREEZE_FLAGS = "app-list-freeze-flags";
public static final String REQUEST_OVERVIEW_LEFT_GESTURE_MARGIN = "overview-left-margin";
public static final String REQUEST_OVERVIEW_RIGHT_GESTURE_MARGIN = "overview-right-margin";
- public static final String REQUEST_ALLOCATED_MEMORY = "allocated-memory";
+ public static final String REQUEST_TOTAL_PSS_KB = "total_pss";
public static boolean sDebugTracing = false;
public static final String REQUEST_ENABLE_DEBUG_TRACING = "enable-debug-tracing";
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index 1405bc5..2a4c5a7 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -29,6 +29,7 @@
import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.Property;
import android.view.MotionEvent;
import android.view.View;
@@ -41,6 +42,7 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.Utilities;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.launcher3.util.TouchController;
@@ -261,6 +263,10 @@
}
case ACTION_CANCEL:
case ACTION_UP:
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_DRAG_TO_WORKSPACE,
+ "BaseDragLayer.ACTION_UP/CANCEL " + ev);
+ }
mTouchDispatchState &= ~TOUCH_DISPATCHING_GESTURE;
mTouchDispatchState &= ~TOUCH_DISPATCHING_VIEW;
break;
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index b146452..3145893 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -562,11 +562,6 @@
*/
private void checkIconResult(View originalView, boolean isOpening) {
CancellationSignal cancellationSignal = new CancellationSignal();
- if (!isOpening) {
- // Hide immediately since the floating view starts at a different location.
- originalView.setVisibility(INVISIBLE);
- cancellationSignal.setOnCancelListener(() -> originalView.setVisibility(VISIBLE));
- }
if (mIconLoadResult == null) {
Log.w(TAG, "No icon load result found in checkIconResult");
@@ -578,7 +573,7 @@
setIcon(originalView, mIconLoadResult.drawable, mIconLoadResult.badge,
mIconLoadResult.iconOffset);
if (isOpening) {
- originalView.setVisibility(INVISIBLE);
+ hideOriginalView(originalView);
}
} else {
mIconLoadResult.onIconLoaded = () -> {
@@ -589,15 +584,26 @@
setIcon(originalView, mIconLoadResult.drawable, mIconLoadResult.badge,
mIconLoadResult.iconOffset);
- // Delay swapping views until the icon is loaded to prevent a flash.
setVisibility(VISIBLE);
- originalView.setVisibility(INVISIBLE);
+ if (isOpening) {
+ // Delay swapping views until the icon is loaded to prevent a flash.
+ hideOriginalView(originalView);
+ }
};
mLoadIconSignal = cancellationSignal;
}
}
}
+ private void hideOriginalView(View originalView) {
+ if (originalView instanceof BubbleTextView) {
+ ((BubbleTextView) originalView).setIconVisible(false);
+ ((BubbleTextView) originalView).setForceHideDot(true);
+ } else {
+ originalView.setVisibility(INVISIBLE);
+ }
+ }
+
private void setBackgroundDrawableBounds(float scale) {
sTmpRect.set(mFinalDrawableBounds);
Utilities.scaleRectAboutCenter(sTmpRect, scale);
@@ -774,7 +780,12 @@
if (hideOriginal) {
if (isOpening) {
- originalView.setVisibility(VISIBLE);
+ if (originalView instanceof BubbleTextView) {
+ ((BubbleTextView) originalView).setIconVisible(true);
+ ((BubbleTextView) originalView).setForceHideDot(false);
+ } else {
+ originalView.setVisibility(VISIBLE);
+ }
view.finish(dragLayer);
} else {
view.mFadeAnimatorSet = view.createFadeAnimation(originalView, dragLayer);
@@ -802,38 +813,33 @@
}
});
- if (mBadge != null && !(mOriginalIcon instanceof FolderIcon)) {
+ if (mBadge != null) {
ObjectAnimator badgeFade = ObjectAnimator.ofInt(mBadge, DRAWABLE_ALPHA, 255);
badgeFade.addUpdateListener(valueAnimator -> invalidate());
fade.play(badgeFade);
}
- if (originalView instanceof BubbleTextView) {
- BubbleTextView btv = (BubbleTextView) originalView;
- btv.forceHideDot(true);
+ if (originalView instanceof IconLabelDotView) {
+ IconLabelDotView view = (IconLabelDotView) originalView;
fade.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- btv.forceHideDot(false);
+ view.setIconVisible(true);
+ view.setForceHideDot(false);
}
});
}
- if (originalView instanceof FolderIcon) {
- FolderIcon folderIcon = (FolderIcon) originalView;
- folderIcon.setBackgroundVisible(false);
- folderIcon.getFolderName().setTextVisibility(false);
- fade.play(folderIcon.getFolderName().createTextAlphaAnimator(true));
+ if (originalView instanceof BubbleTextView) {
+ BubbleTextView btv = (BubbleTextView) originalView;
fade.addListener(new AnimatorListenerAdapter() {
@Override
- public void onAnimationEnd(Animator animation) {
- folderIcon.setBackgroundVisible(true);
- if (folderIcon.hasDot()) {
- folderIcon.animateDotScale(0, 1f);
- }
+ public void onAnimationStart(Animator animation) {
+ btv.setIconVisible(true);
}
});
- } else {
+ fade.play(ObjectAnimator.ofInt(btv.getIcon(), DRAWABLE_ALPHA, 0, 255));
+ } else if (!(originalView instanceof FolderIcon)) {
fade.play(ObjectAnimator.ofFloat(originalView, ALPHA, 0f, 1f));
}
diff --git a/src/com/android/launcher3/views/IconLabelDotView.java b/src/com/android/launcher3/views/IconLabelDotView.java
new file mode 100644
index 0000000..057caaf
--- /dev/null
+++ b/src/com/android/launcher3/views/IconLabelDotView.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2019 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.views;
+
+/**
+ * A view that has an icon, label, and notification dot.
+ */
+public interface IconLabelDotView {
+ void setIconVisible(boolean visible);
+ void setForceHideDot(boolean hide);
+}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 761253d..86635ed 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -188,14 +188,6 @@
}
}
- protected void lockRotation(boolean naturalOrientation) throws RemoteException {
- if (naturalOrientation) {
- mDevice.setOrientationNatural();
- } else {
- mDevice.setOrientationRight();
- }
- }
-
protected void clearLauncherData() throws IOException, InterruptedException {
if (TestHelpers.isInLauncherProcess()) {
LauncherSettings.Settings.call(mTargetContext.getContentResolver(),
@@ -277,6 +269,12 @@
// Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide
// flakiness.
+ protected <T> T getOnceNotNull(String message, Function<Launcher, T> f) {
+ return getOnceNotNull(message, f, DEFAULT_ACTIVITY_TIMEOUT);
+ }
+
+ // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide
+ // flakiness.
protected void waitForLauncherCondition(
String message, Function<Launcher, Boolean> condition, long timeout) {
if (!TestHelpers.isInLauncherProcess()) return;
@@ -285,6 +283,20 @@
// Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide
// flakiness.
+ protected <T> T getOnceNotNull(String message, Function<Launcher, T> f, long timeout) {
+ if (!TestHelpers.isInLauncherProcess()) return null;
+
+ final Object[] output = new Object[1];
+ Wait.atMost(message, () -> {
+ final Object fromLauncher = getFromLauncher(f);
+ output[0] = fromLauncher;
+ return fromLauncher != null;
+ }, timeout);
+ return (T) output[0];
+ }
+
+ // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide
+ // flakiness.
protected void waitForLauncherCondition(
String message,
Runnable testThreadAction, Function<Launcher, Boolean> condition,
diff --git a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
index ddcb4da..80bb3ed 100644
--- a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
+++ b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
@@ -44,8 +44,11 @@
} finally {
mTest.mDevice.setOrientationNatural();
mTest.executeOnLauncher(launcher ->
- launcher.getRotationHelper().forceAllowRotationForTesting(
- false));
+ {
+ if (launcher != null) {
+ launcher.getRotationHelper().forceAllowRotationForTesting(false);
+ }
+ });
mTest.mLauncher.setExpectedRotation(Surface.ROTATION_0);
}
}
diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
index 3206a69..5c38c8d 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
@@ -41,7 +41,6 @@
import com.android.launcher3.util.rule.ShellCommandRule;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -69,34 +68,22 @@
}
@Test
+ @PortraitLandscape
public void testWidgetConfig() throws Throwable {
- runTest(false, true);
+ runTest(true);
}
@Test
- @Ignore // b/121280703
- public void testWidgetConfig_rotate() throws Throwable {
- runTest(true, true);
- }
-
- @Test
+ @PortraitLandscape
public void testConfigCancelled() throws Throwable {
- runTest(false, false);
+ runTest(false);
}
- @Test
- @Ignore // b/121280703
- public void testConfigCancelled_rotate() throws Throwable {
- runTest(true, false);
- }
/**
- * @param rotateConfig should the config screen be rotated
* @param acceptConfig accept the config activity
*/
- private void runTest(boolean rotateConfig, boolean acceptConfig) throws Throwable {
- lockRotation(true);
-
+ private void runTest(boolean acceptConfig) throws Throwable {
clearHomescreen();
mDevice.pressHome();
@@ -110,13 +97,6 @@
// Widget id for which the config activity was opened
mWidgetId = monitor.getWidgetId();
- if (rotateConfig) {
- // Rotate the screen and verify that the config activity is recreated
- monitor = new WidgetConfigStartupMonitor();
- lockRotation(false);
- assertEquals(mWidgetId, monitor.getWidgetId());
- }
-
// Verify that the widget id is valid and bound
assertNotNull(mAppWidgetManager.getAppWidgetInfo(mWidgetId));
diff --git a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
index 276c614..b9abc2e 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
@@ -26,7 +26,6 @@
import com.android.launcher3.ui.TestViewHelpers;
import com.android.launcher3.util.rule.ShellCommandRule;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -41,19 +40,8 @@
@Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
@Test
- public void testDragIcon_portrait() throws Throwable {
- lockRotation(true);
- performTest();
- }
-
- @Test
- @Ignore // b/121280703
- public void testDragIcon_landscape() throws Throwable {
- lockRotation(false);
- performTest();
- }
-
- private void performTest() throws Throwable {
+ @PortraitLandscape
+ public void testDragIcon() throws Throwable {
clearHomescreen();
mDevice.pressHome();
diff --git a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
index a9a5090..07129dd 100644
--- a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
@@ -128,8 +128,6 @@
if (!Utilities.ATLEAST_OREO) {
return;
}
- lockRotation(true);
-
clearHomescreen();
mDevice.pressHome();
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 0bd6362..14f2c85 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -957,8 +957,8 @@
getTestInfo(TestProtocol.REQUEST_DISABLE_DEBUG_TRACING);
}
- public long getAllocatedMemory() {
- return getTestInfo(TestProtocol.REQUEST_ALLOCATED_MEMORY).
- getLong(TestProtocol.TEST_INFO_RESPONSE_FIELD);
+ public int getTotalPssKb() {
+ return getTestInfo(TestProtocol.REQUEST_TOTAL_PSS_KB).
+ getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
}
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index 2495933..f3295d0 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.fail;
import android.graphics.Point;
+import android.graphics.Rect;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.BySelector;
@@ -31,7 +32,8 @@
* All widgets container.
*/
public final class Widgets extends LauncherInstrumentation.VisibleContainer {
- private static final int FLING_SPEED = 1500;
+ private static final Rect MARGINS = new Rect(100, 100, 100, 100);
+ private static final int FLING_STEPS = 10;
Widgets(LauncherInstrumentation launcher) {
super(launcher);
@@ -46,11 +48,7 @@
"want to fling forward in widgets")) {
LauncherInstrumentation.log("Widgets.flingForward enter");
final UiObject2 widgetsContainer = verifyActiveContainer();
- widgetsContainer.setGestureMargins(0, 0, 0,
- ResourceUtils.getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE,
- mLauncher.getResources()) + 1);
- widgetsContainer.fling(Direction.DOWN,
- (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
+ mLauncher.scroll(widgetsContainer, Direction.DOWN, 1f, MARGINS, FLING_STEPS);
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung forward")) {
verifyActiveContainer();
}
@@ -66,10 +64,7 @@
"want to fling backwards in widgets")) {
LauncherInstrumentation.log("Widgets.flingBackward enter");
final UiObject2 widgetsContainer = verifyActiveContainer();
- widgetsContainer.setGestureMargin(100);
- widgetsContainer.fling(Direction.UP,
- (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
- mLauncher.waitForIdle();
+ mLauncher.scroll(widgetsContainer, Direction.UP, 1f, MARGINS, FLING_STEPS);
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung back")) {
verifyActiveContainer();
}
@@ -101,7 +96,7 @@
return new Widget(mLauncher, widget);
}
if (++i > 40) fail("Too many attempts");
- widgetsContainer.scroll(Direction.DOWN, 1f);
+ mLauncher.scroll(widgetsContainer, Direction.DOWN, 1f, MARGINS, 50);
}
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 639902f..510ea14 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -21,6 +21,7 @@
import static junit.framework.TestCase.assertTrue;
import android.graphics.Point;
+import android.graphics.Rect;
import android.os.SystemClock;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -40,6 +41,7 @@
private static final float FLING_SPEED =
LauncherInstrumentation.isAvd() ? 1500.0F : 3500.0F;
private static final int DRAG_DURACTION = 2000;
+ private static final int FLING_STEPS = 10;
private final UiObject2 mHotseat;
Workspace(LauncherInstrumentation launcher) {
@@ -180,9 +182,9 @@
*/
public void flingForward() {
final UiObject2 workspace = verifyActiveContainer();
- workspace.setGestureMargins(0, 0, mLauncher.getEdgeSensitivityWidth(), 0);
- workspace.fling(Direction.RIGHT, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
- mLauncher.waitForIdle();
+ mLauncher.scroll(workspace, Direction.RIGHT, 1f,
+ new Rect(0, 0, mLauncher.getEdgeSensitivityWidth(), 0),
+ FLING_STEPS);
verifyActiveContainer();
}
@@ -192,9 +194,9 @@
*/
public void flingBackward() {
final UiObject2 workspace = verifyActiveContainer();
- workspace.setGestureMargins(mLauncher.getEdgeSensitivityWidth(), 0, 0, 0);
- workspace.fling(Direction.LEFT, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
- mLauncher.waitForIdle();
+ mLauncher.scroll(workspace, Direction.LEFT, 1f,
+ new Rect(mLauncher.getEdgeSensitivityWidth(), 0, 0, 0),
+ FLING_STEPS);
verifyActiveContainer();
}