Merge "Merging duplicate logic for deferred drop handling in Worksace and Folder" into ub-launcher3-master
diff --git a/res/layout/gradient_bg.xml b/res/layout/gradient_bg.xml
index db448d7..6c6626c 100644
--- a/res/layout/gradient_bg.xml
+++ b/res/layout/gradient_bg.xml
@@ -20,5 +20,4 @@
android:id="@+id/gradient_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:visibility="gone"
launcher:layout_ignoreInsets="true" />
\ No newline at end of file
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 1e3626d..d8cb06c 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -119,7 +119,6 @@
import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
import com.android.launcher3.util.ActivityResultInfo;
import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.ComponentKeyMapper;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.PackageManagerHelper;
@@ -203,7 +202,7 @@
static final String APPS_VIEW_SHOWN = "launcher.apps_view_shown";
/** The different states that Launcher can be in. */
- enum State { NONE, WORKSPACE, WORKSPACE_SPRING_LOADED, APPS, APPS_SPRING_LOADED,
+ enum State { WORKSPACE, WORKSPACE_SPRING_LOADED, APPS, APPS_SPRING_LOADED,
WIDGETS, WIDGETS_SPRING_LOADED }
@Thunk State mState = State.WORKSPACE;
@@ -250,11 +249,6 @@
// that results in widgets being inflated in the wrong orientation.
private int mOrientation;
- // We set the state in both onCreate and then onNewIntent in some cases, which causes both
- // scroll issues (because the workspace may not have been measured yet) and extra work.
- // Instead, just save the state that we need to restore Launcher to, and commit it in onResume.
- private State mOnResumeState = State.NONE;
-
private SpannableStringBuilder mDefaultKeySsb = null;
@Thunk boolean mWorkspaceLoading = true;
@@ -858,17 +852,6 @@
TraceHelper.partitionSection("ON_RESUME", "superCall");
getUserEventDispatcher().resetElapsedSessionMillis();
-
- // Restore the previous launcher state
- if (mOnResumeState == State.WORKSPACE) {
- showWorkspace(false);
- } else if (mOnResumeState == State.APPS) {
- showAppsView(false /* animated */);
- } else if (mOnResumeState == State.WIDGETS) {
- showWidgetsView(false, false);
- }
- mOnResumeState = State.NONE;
-
mPaused = false;
if (mOnResumeNeedsLoad) {
setWorkspaceLoading(true);
@@ -1071,8 +1054,10 @@
State[] stateValues = State.values();
State state = (stateOrdinal >= 0 && stateOrdinal < stateValues.length)
? stateValues[stateOrdinal] : State.WORKSPACE;
- if (state == State.APPS || state == State.WIDGETS) {
- mOnResumeState = state;
+ if (state == State.APPS) {
+ showAppsView(false /* animated */);
+ } else if (state == State.WIDGETS) {
+ showWidgetsView(false, false);
}
PendingRequestArgs requestArgs = savedState.getParcelable(RUNTIME_STATE_PENDING_REQUEST_ARGS);
@@ -1484,15 +1469,7 @@
// In all these cases, only animate if we're already on home
AbstractFloatingView.closeAllOpenViews(this, alreadyOnHome);
- exitSpringLoadedDragMode();
-
- // If we are already on home, then just animate back to the workspace,
- // otherwise, just wait until onResume to set the state back to Workspace
- if (alreadyOnHome) {
- showWorkspace(true);
- } else {
- mOnResumeState = State.WORKSPACE;
- }
+ showWorkspace(alreadyOnHome /* animated */);
final View v = getWindow().peekDecorView();
if (v != null && v.getWindowToken() != null) {
@@ -2537,11 +2514,11 @@
}
public boolean isAppsViewVisible() {
- return (mState == State.APPS) || (mOnResumeState == State.APPS);
+ return mState == State.APPS;
}
public boolean isWidgetsViewVisible() {
- return (mState == State.WIDGETS) || (mOnResumeState == State.WIDGETS);
+ return mState == State.WIDGETS;
}
@Override
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 9794e31..0ae4722 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -2030,7 +2030,7 @@
if (dropOverView instanceof FolderIcon) {
FolderIcon fi = (FolderIcon) dropOverView;
if (fi.acceptDrop(d.dragInfo)) {
- fi.onDrop(d);
+ fi.onDrop(d, false /* itemReturnedOnFailedDrop */);
// if the drag started here, we need to remove it from the workspace
if (!external) {
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 2cc0781..b844ba3 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -275,8 +275,7 @@
private void updateAllAppsBg(float progress) {
// gradient
if (mGradientView == null) {
- mGradientView = (GradientView) mLauncher.findViewById(R.id.gradient_bg);
- mGradientView.setVisibility(View.VISIBLE);
+ mGradientView = mLauncher.findViewById(R.id.gradient_bg);
}
mGradientView.setProgress(progress);
}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 8d75db4..b930ad3 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -867,7 +867,7 @@
mItemsInvalidated = true;
try (SuppressInfoChanges s = new SuppressInfoChanges()) {
- mFolderIcon.onDrop(d);
+ mFolderIcon.onDrop(d, true /* itemReturnedOnFailedDrop */);
}
}
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index bb0a726..3998888 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -100,6 +100,7 @@
ClippedFolderIconLayoutRule mPreviewLayoutRule;
private PreviewItemManager mPreviewItemManager;
private PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0);
+ private List<BubbleTextView> mCurrentPreviewItems = new ArrayList<>();
boolean mAnimating = false;
private Rect mTempBounds = new Rect();
@@ -198,7 +199,7 @@
private void setFolder(Folder folder) {
mFolder = folder;
mPreviewVerifier = new FolderIconPreviewVerifier(mLauncher.getDeviceProfile().inv);
- mPreviewItemManager.updateItemDrawingParams(false);
+ updatePreviewItems(false);
}
private boolean willAcceptItem(ItemInfo item) {
@@ -262,7 +263,8 @@
.start();
// This will animate the dragView (srcView) into the new folder
- onDrop(srcInfo, srcView, dstRect, scaleRelativeToDragLayer, 1, postAnimationRunnable);
+ onDrop(srcInfo, srcView, dstRect, scaleRelativeToDragLayer, 1, postAnimationRunnable,
+ false /* itemReturnedOnFailedDrop */);
}
public void performDestroyAnimation(Runnable onCompleteRunnable) {
@@ -277,7 +279,8 @@
}
private void onDrop(final ShortcutInfo item, DragView animateView, Rect finalRect,
- float scaleRelativeToDragLayer, int index, Runnable postAnimationRunnable) {
+ float scaleRelativeToDragLayer, int index, Runnable postAnimationRunnable,
+ boolean itemReturnedOnFailedDrop) {
item.cellX = -1;
item.cellY = -1;
@@ -305,21 +308,25 @@
workspace.resetTransitionTransform((CellLayout) getParent().getParent());
}
+ int numItemsInPreview = Math.min(MAX_NUM_ITEMS_IN_PREVIEW, index + 1);
boolean itemAdded = false;
- if (index >= MAX_NUM_ITEMS_IN_PREVIEW) {
- List<BubbleTextView> oldPreviewItems = getPreviewItemsOnPage(0);
+ if (itemReturnedOnFailedDrop || index >= MAX_NUM_ITEMS_IN_PREVIEW) {
+ List<BubbleTextView> oldPreviewItems = new ArrayList<>(mCurrentPreviewItems);
addItem(item, false);
- List<BubbleTextView> newPreviewItems = getPreviewItemsOnPage(0);
+ mCurrentPreviewItems.clear();
+ mCurrentPreviewItems.addAll(getPreviewItems());
- if (!oldPreviewItems.containsAll(newPreviewItems)) {
- for (int i = 0; i < newPreviewItems.size(); ++i) {
- if (newPreviewItems.get(i).getTag().equals(item)) {
+ 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;
}
}
- mPreviewItemManager.onDrop(oldPreviewItems, newPreviewItems, item);
+
+ mPreviewItemManager.hidePreviewItem(index, true);
+ mPreviewItemManager.onDrop(oldPreviewItems, mCurrentPreviewItems, item);
itemAdded = true;
} else {
removeItem(item, false);
@@ -331,7 +338,7 @@
}
int[] center = new int[2];
- float scale = getLocalCenterForIndex(index, index + 1, center);
+ float scale = getLocalCenterForIndex(index, numItemsInPreview, center);
center[0] = (int) Math.round(scaleRelativeToDragLayer * center[0]);
center[1] = (int) Math.round(scaleRelativeToDragLayer * center[1]);
@@ -362,7 +369,7 @@
}
}
- public void onDrop(DragObject d) {
+ public void onDrop(DragObject d, boolean itemReturnedOnFailedDrop) {
ShortcutInfo item;
if (d.dragInfo instanceof AppInfo) {
// Came from all apps -- make a copy
@@ -374,7 +381,8 @@
item = (ShortcutInfo) d.dragInfo;
}
mFolder.notifyDrop();
- onDrop(item, d.dragView, null, 1.0f, mInfo.contents.size(), d.postAnimationRunnable);
+ onDrop(item, d.dragView, null, 1.0f, mInfo.contents.size(), d.postAnimationRunnable,
+ itemReturnedOnFailedDrop);
}
public void setBadgeInfo(FolderBadgeInfo badgeInfo) {
@@ -545,11 +553,17 @@
@Override
public void onItemsChanged(boolean animate) {
- mPreviewItemManager.updateItemDrawingParams(animate);
+ updatePreviewItems(animate);
invalidate();
requestLayout();
}
+ private void updatePreviewItems(boolean animate) {
+ mPreviewItemManager.updatePreviewItems(animate);
+ mCurrentPreviewItems.clear();
+ mCurrentPreviewItems.addAll(getPreviewItems());
+ }
+
@Override
public void prepareAutoUpdate() {
}
diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java
index 5d40010..06d3eb1 100644
--- a/src/com/android/launcher3/folder/PreviewItemManager.java
+++ b/src/com/android/launcher3/folder/PreviewItemManager.java
@@ -110,7 +110,7 @@
mIcon.mPreviewLayoutRule.init(mIcon.mBackground.previewSize, mIntrinsicIconSize,
Utilities.isRtl(mIcon.getResources()));
- updateItemDrawingParams(false);
+ updatePreviewItems(false);
}
}
@@ -185,6 +185,11 @@
}
public void hidePreviewItem(int index, boolean hidden) {
+ // If there are more params than visible in the preview, they are used for enter/exit
+ // animation purposes and they were added to the front of the list.
+ // To index the params properly, we need to skip these params.
+ index = index + Math.max(mFirstPageParams.size() - MAX_NUM_ITEMS_IN_PREVIEW, 0);
+
PreviewItemDrawingParams params = index < mFirstPageParams.size() ?
mFirstPageParams.get(index) : null;
if (params != null) {
@@ -266,7 +271,7 @@
}
}
- void updateItemDrawingParams(boolean animate) {
+ void updatePreviewItems(boolean animate) {
buildParamsForPage(0, mFirstPageParams, animate);
}
@@ -310,8 +315,8 @@
int prevIndex = newParams.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, newParams.indexOf(moveIn.get(i)),
+ numItems);
}
// Items that are moving into new positions within the preview.
@@ -319,7 +324,7 @@
int oldIndex = oldParams.indexOf(newParams.get(newIndex));
if (oldIndex >= 0 && newIndex != oldIndex) {
PreviewItemDrawingParams p = params.get(newIndex);
- updateTransitionParam(p, newParams.get(newIndex), oldIndex, newIndex);
+ updateTransitionParam(p, newParams.get(newIndex), oldIndex, newIndex, numItems);
}
}
@@ -330,7 +335,7 @@
BubbleTextView item = moveOut.get(i);
int oldIndex = oldParams.indexOf(item);
PreviewItemDrawingParams p = computePreviewItemDrawingParams(oldIndex, numItems, null);
- updateTransitionParam(p, item, oldIndex, EXIT_INDEX);
+ updateTransitionParam(p, item, oldIndex, EXIT_INDEX, numItems);
params.add(0, p); // We want these items first so that they are on drawn last.
}
@@ -342,7 +347,7 @@
}
private void updateTransitionParam(final PreviewItemDrawingParams p, BubbleTextView btv,
- int prevIndex, int newIndex) {
+ 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
@@ -350,9 +355,8 @@
p.drawable.setCallback(mIcon);
}
- FolderPreviewItemAnim anim = new FolderPreviewItemAnim(this, p, prevIndex,
- MAX_NUM_ITEMS_IN_PREVIEW, newIndex, MAX_NUM_ITEMS_IN_PREVIEW,
- DROP_IN_ANIMATION_DURATION, null);
+ FolderPreviewItemAnim anim = new FolderPreviewItemAnim(this, p, prevIndex, numItems,
+ newIndex, numItems, DROP_IN_ANIMATION_DURATION, null);
if (p.anim != null && !p.anim.hasEqualFinalState(anim)) {
p.anim.cancel();
}
diff --git a/src/com/android/launcher3/notification/NotificationGroup.java b/src/com/android/launcher3/notification/NotificationGroup.java
new file mode 100644
index 0000000..bce2117
--- /dev/null
+++ b/src/com/android/launcher3/notification/NotificationGroup.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 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.notification;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Contains data related to a group of notifications, like the group summary key and the child keys.
+ */
+public class NotificationGroup {
+ private String mGroupSummaryKey;
+ private Set<String> mChildKeys;
+
+ public NotificationGroup() {
+ mChildKeys = new HashSet<>();
+ }
+
+ public void setGroupSummaryKey(String groupSummaryKey) {
+ mGroupSummaryKey = groupSummaryKey;
+ }
+
+ public String getGroupSummaryKey() {
+ return mGroupSummaryKey;
+ }
+
+ public void addChildKey(String childKey) {
+ mChildKeys.add(childKey);
+ }
+
+ public void removeChildKey(String childKey) {
+ mChildKeys.remove(childKey);
+ }
+
+ public boolean isEmpty() {
+ return mChildKeys.isEmpty();
+ }
+}
diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java
index 9126626..7b70df7 100644
--- a/src/com/android/launcher3/notification/NotificationListener.java
+++ b/src/com/android/launcher3/notification/NotificationListener.java
@@ -38,7 +38,9 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING;
@@ -66,6 +68,8 @@
private final Handler mWorkerHandler;
private final Handler mUiHandler;
private final Ranking mTempRanking = new Ranking();
+ /** Maps groupKey's to the corresponding group of notifications. */
+ private final Map<String, NotificationGroup> mNotificationGroupMap = new HashMap<>();
private SettingsObserver mNotificationBadgingObserver;
@@ -227,6 +231,15 @@
NotificationKeyData.fromNotification(sbn));
mWorkerHandler.obtainMessage(MSG_NOTIFICATION_REMOVED, packageUserKeyAndNotificationKey)
.sendToTarget();
+
+ NotificationGroup notificationGroup = mNotificationGroupMap.get(sbn.getGroupKey());
+ if (notificationGroup != null) {
+ notificationGroup.removeChildKey(sbn.getKey());
+ if (notificationGroup.isEmpty()) {
+ cancelNotification(notificationGroup.getGroupSummaryKey());
+ mNotificationGroupMap.remove(sbn.getGroupKey());
+ }
+ }
}
/** This makes a potentially expensive binder call and should be run on a background thread. */
@@ -264,18 +277,34 @@
}
private boolean shouldBeFilteredOut(StatusBarNotification sbn) {
+ Notification notification = sbn.getNotification();
+
+ boolean isGroupHeader = (notification.flags & Notification.FLAG_GROUP_SUMMARY) != 0;
+ if (sbn.isGroup()) {
+ // Maintain group info so we can cancel the summary when the last child is canceled.
+ NotificationGroup notificationGroup = mNotificationGroupMap.get(sbn.getGroupKey());
+ if (notificationGroup == null) {
+ notificationGroup = new NotificationGroup();
+ mNotificationGroupMap.put(sbn.getGroupKey(), notificationGroup);
+ }
+ if (isGroupHeader) {
+ notificationGroup.setGroupSummaryKey(sbn.getKey());
+ } else {
+ notificationGroup.addChildKey(sbn.getKey());
+ }
+ }
+
getCurrentRanking().getRanking(sbn.getKey(), mTempRanking);
if (!mTempRanking.canShowBadge()) {
return true;
}
- Notification notification = sbn.getNotification();
if (mTempRanking.getChannel().getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID)) {
// Special filtering for the default, legacy "Miscellaneous" channel.
if ((notification.flags & Notification.FLAG_ONGOING_EVENT) != 0) {
return true;
}
}
- boolean isGroupHeader = (notification.flags & Notification.FLAG_GROUP_SUMMARY) != 0;
+
CharSequence title = notification.extras.getCharSequence(Notification.EXTRA_TITLE);
CharSequence text = notification.extras.getCharSequence(Notification.EXTRA_TEXT);
boolean missingTitleAndText = TextUtils.isEmpty(title) && TextUtils.isEmpty(text);
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 432efa7..7aa50a4 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -107,7 +107,6 @@
onWidgetsBound();
mLauncher.getDragLayer().addView(mGradientBackground);
- mGradientBackground.setVisibility(VISIBLE);
mLauncher.getDragLayer().addView(this);
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
setTranslationY(mTranslationYClosed);