Merge "Prevent blinking when user presses home." into ub-launcher3-master
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
index d230de6..74d3cba 100644
--- a/quickstep/libs/sysui_shared.jar
+++ b/quickstep/libs/sysui_shared.jar
Binary files differ
diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index 35246b6..11bc883 100644
--- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -30,7 +30,6 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
-import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.Build;
@@ -41,13 +40,13 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Interpolator;
-import android.widget.ImageView;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.InsettableFrameLayout.LayoutParams;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.graphics.DrawableFactory;
import com.android.systemui.shared.system.ActivityCompat;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
@@ -85,7 +84,7 @@
private final float mContentTransY;
private final float mWorkspaceTransY;
- private ImageView mFloatingView;
+ private View mFloatingView;
private boolean mIsRtl;
private LauncherTransitionAnimator mCurrentAnimator;
@@ -243,11 +242,11 @@
*/
private AnimatorSet getIconAnimator(View v) {
boolean isBubbleTextView = v instanceof BubbleTextView;
- mFloatingView = new ImageView(mLauncher);
- if (isBubbleTextView) {
+ mFloatingView = new View(mLauncher);
+ if (isBubbleTextView && v.getTag() instanceof ItemInfoWithIcon ) {
// Create a copy of the app icon
- Bitmap iconBitmap = ((FastBitmapDrawable) ((BubbleTextView) v).getIcon()).getBitmap();
- mFloatingView.setImageDrawable(new FastBitmapDrawable(iconBitmap));
+ mFloatingView.setBackground(
+ DrawableFactory.get(mLauncher).newIcon((ItemInfoWithIcon) v.getTag()));
}
// Position the floating view exactly on top of the original
diff --git a/quickstep/src/com/android/quickstep/LauncherLayoutListener.java b/quickstep/src/com/android/quickstep/LauncherLayoutListener.java
index 2a7e5c4..fbdbe7a 100644
--- a/quickstep/src/com/android/quickstep/LauncherLayoutListener.java
+++ b/quickstep/src/com/android/quickstep/LauncherLayoutListener.java
@@ -42,12 +42,6 @@
@Override
public void setInsets(Rect insets) {
- requestLayout();
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
if (mHandler != null) {
mHandler.onLauncherLayoutChanged();
}
diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
index 86e28f2..61d4790 100644
--- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
@@ -279,10 +279,11 @@
new RecentsAnimationListener() {
public void onAnimationStart(
RecentsAnimationControllerCompat controller,
- RemoteAnimationTargetCompat[] apps) {
+ RemoteAnimationTargetCompat[] apps, Rect homeContentInsets,
+ Rect minimizedHomeBounds) {
if (mInteractionHandler == handler) {
- handler.setRecentsAnimation(controller, apps);
-
+ handler.setRecentsAnimation(controller, apps, homeContentInsets,
+ minimizedHomeBounds);
} else {
controller.finish(false /* toHome */);
}
@@ -290,7 +291,7 @@
public void onAnimationCanceled() {
if (mInteractionHandler == handler) {
- handler.setRecentsAnimation(null, null);
+ handler.setRecentsAnimation(null, null, null, null);
}
}
}, null, null);
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 028af9a..6082aea 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -34,6 +34,7 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Matrix;
+import android.graphics.Point;
import android.graphics.Rect;
import android.os.Build;
import android.os.Handler;
@@ -91,10 +92,23 @@
private static final float MIN_PROGRESS_FOR_OVERVIEW = 0.5f;
- private final Rect mStableInsets = new Rect();
+ // The bounds of the source app in device coordinates
+ private final Rect mSourceStackBounds = new Rect();
+ // The insets of the source app
+ private final Rect mSourceInsets = new Rect();
+ // The source app bounds with the source insets applied, in the source app window coordinates
private final Rect mSourceRect = new Rect();
+ // The insets to be used for clipping the app window, which can be larger than mSourceInsets
+ // if the aspect ratio of the target is smaller than the aspect ratio of the source rect. In
+ // app window coordinates.
+ private final Rect mSourceWindowClipInsets = new Rect();
+ // The bounds of launcher (not including insets) in device coordinates
+ private final Rect mHomeStackBounds = new Rect();
+ // The bounds of the task view in launcher window coordinates
private final Rect mTargetRect = new Rect();
+ // The interpolated rect from the source app rect to the target rect
private final Rect mCurrentRect = new Rect();
+ // The clip rect in source app window coordinates
private final Rect mClipRect = new Rect();
private final RectEvaluator mRectEvaluator = new RectEvaluator(mCurrentRect);
private DeviceProfile mDp;
@@ -135,16 +149,6 @@
WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context) {
mContext = context;
mRunningTaskId = runningTaskInfo.id;
-
- WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
-
- DeviceProfile dp = LauncherAppState.getIDP(mContext).getDeviceProfile(mContext);
- // TODO: If in multi window mode, dp = dp.getMultiWindowProfile()
- dp = dp.copy(mContext);
- // TODO: Use different insets for multi-window mode
- dp.updateInsets(mStableInsets);
-
- initTransitionEndpoints(dp);
initStateCallbacks();
}
@@ -154,6 +158,8 @@
this::initializeLauncherAnimationController);
mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN,
this::launcherFrameDrawn);
+ mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_GESTURE_STARTED,
+ this::notifyGestureStarted);
mStateCallback.addCallback(STATE_SCALED_CONTROLLER_APP | STATE_APP_CONTROLLER_RECEIVED,
this::resumeLastTask);
@@ -187,13 +193,33 @@
private void initTransitionEndpoints(DeviceProfile dp) {
mDp = dp;
- RecentsView.getPageRect(dp, mContext, mTargetRect);
- mSourceRect.set(0, 0, dp.widthPx - mStableInsets.left - mStableInsets.right,
- dp.heightPx - mStableInsets.top - mStableInsets.bottom);
- mTransitionDragLength = dp.hotseatBarSizePx + (dp.isVerticalBarLayout()
- ? (dp.hotseatBarSidePaddingPx + (dp.isSeascape() ? mStableInsets.left : mStableInsets.right))
- : mStableInsets.bottom);
+ mSourceRect.set(0, 0, dp.widthPx - mSourceInsets.left - mSourceInsets.right,
+ dp.heightPx - mSourceInsets.top - mSourceInsets.bottom);
+ RecentsView.getPageRect(dp, mContext, mTargetRect);
+ mTargetRect.offset(mHomeStackBounds.left - mSourceStackBounds.left,
+ mHomeStackBounds.top - mSourceStackBounds.top);
+
+ // Calculate the clip based on the target rect (since the content insets and the
+ // launcher insets may differ, so the aspect ratio of the target rect can differ
+ // from the source rect. The difference between the target rect (scaled to the
+ // source rect) is the amount to clip on each edge.
+ Rect scaledTargetRect = new Rect(mTargetRect);
+ Utilities.scaleRectAboutCenter(scaledTargetRect,
+ (float) mSourceRect.width() / mTargetRect.width());
+ scaledTargetRect.offsetTo(mSourceInsets.left, mSourceInsets.top);
+ mSourceWindowClipInsets.set(scaledTargetRect.left, scaledTargetRect.top,
+ mDp.widthPx - scaledTargetRect.right,
+ mDp.heightPx - scaledTargetRect.bottom);
+
+ Rect targetInsets = dp.getInsets();
+ mTransitionDragLength = dp.hotseatBarSizePx;
+ if (dp.isVerticalBarLayout()) {
+ int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
+ mTransitionDragLength += dp.hotseatBarSidePaddingPx + hotseatInset;
+ } else {
+ mTransitionDragLength += targetInsets.bottom;
+ }
}
private long getFadeInDuration() {
@@ -220,6 +246,7 @@
mStateCallback.setState(oldState);
mLauncherLayoutListener.setHandler(null);
}
+ mWasLauncherAlreadyVisible = alreadyOnHome;
mLauncher = launcher;
LauncherState startState = mLauncher.getStateManager().getState();
@@ -229,7 +256,6 @@
mLauncher.getStateManager().setRestState(startState);
AbstractFloatingView.closeAllOpenViews(launcher, alreadyOnHome);
- mWasLauncherAlreadyVisible = alreadyOnHome;
mRecentsView = mLauncher.getOverviewPanel();
mLauncherLayoutListener = new LauncherLayoutListener(mLauncher);
@@ -268,18 +294,14 @@
}
});
state = STATE_LAUNCHER_PRESENT;
+
+ // Optimization, hide the all apps view to prevent layout while initializing
+ mLauncher.getAppsView().setVisibility(View.GONE);
}
mRecentsView.showTask(mRunningTaskId);
mLauncherLayoutListener.open();
- // Optimization
- // We are using the internal device profile as launcher may not have got the insets yet.
- if (!mDp.isVerticalBarLayout()) {
- // All-apps search box is visible in vertical bar layout.
- mLauncher.getAppsView().setVisibility(View.GONE);
- }
-
mStateCallback.setState(state);
return true;
}
@@ -351,7 +373,6 @@
* Called by {@link #mLauncherLayoutListener} when launcher layout changes
*/
public void onLauncherLayoutChanged() {
- WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
initTransitionEndpoints(mLauncher.getDeviceProfile());
if (!mWasLauncherAlreadyVisible) {
@@ -392,14 +413,14 @@
mRectEvaluator.evaluate(shift, mSourceRect, mTargetRect);
float scale = (float) mCurrentRect.width() / mSourceRect.width();
- mClipRect.left = mSourceRect.left;
- mClipRect.top = (int) (mStableInsets.top * shift);
- mClipRect.bottom = (int) (mDp.heightPx - (mStableInsets.bottom * shift));
- mClipRect.right = mSourceRect.right;
+ mClipRect.left = (int) (mSourceWindowClipInsets.left * shift);
+ mClipRect.top = (int) (mSourceWindowClipInsets.top * shift);
+ mClipRect.right = (int) (mDp.widthPx - (mSourceWindowClipInsets.right * shift));
+ mClipRect.bottom = (int) (mDp.heightPx - (mSourceWindowClipInsets.bottom * shift));
mTmpMatrix.setScale(scale, scale, 0, 0);
- mTmpMatrix.postTranslate(mCurrentRect.left - mStableInsets.left * scale * shift,
- mCurrentRect.top - mStableInsets.top * scale * shift);
+ mTmpMatrix.postTranslate(mCurrentRect.left - mSourceInsets.left * scale * shift,
+ mCurrentRect.top - mSourceInsets.top * scale * shift);
TransactionCompat transaction = new TransactionCompat();
for (RemoteAnimationTargetCompat app : mRecentsAnimationWrapper.targets) {
if (app.mode == MODE_CLOSING) {
@@ -423,16 +444,63 @@
}
public void setRecentsAnimation(RecentsAnimationControllerCompat controller,
- RemoteAnimationTargetCompat[] apps) {
+ RemoteAnimationTargetCompat[] apps, Rect homeContentInsets, Rect minimizedHomeBounds) {
+ if (apps != null) {
+ // Use the top closing app to determine the insets for the animation
+ for (RemoteAnimationTargetCompat target : apps) {
+ if (target.mode == MODE_CLOSING) {
+ DeviceProfile dp = LauncherAppState.getIDP(mContext).getDeviceProfile(mContext);
+ if (minimizedHomeBounds != null) {
+ mHomeStackBounds.set(minimizedHomeBounds);
+ dp = dp.getMultiWindowProfile(mContext,
+ new Point(minimizedHomeBounds.width(), minimizedHomeBounds.height()));
+ dp.updateInsets(homeContentInsets);
+ } else {
+ mHomeStackBounds.set(new Rect(0, 0, dp.widthPx, dp.heightPx));
+ // TODO: Workaround for an existing issue where the home content insets are
+ // not valid immediately after rotation, just use the stable insets for now
+ Rect insets = new Rect();
+ WindowManagerWrapper.getInstance().getStableInsets(insets);
+ dp.updateInsets(insets);
+ }
+
+ // Initialize the start and end animation bounds
+ // TODO: Remove once platform is updated
+ try {
+ mSourceInsets.set(target.getContentInsets());
+ } catch (Error e) {
+ // TODO: Remove once platform is updated, use stable insets as fallback
+ WindowManagerWrapper.getInstance().getStableInsets(mSourceInsets);
+ }
+ mSourceStackBounds.set(target.sourceContainerBounds);
+
+ initTransitionEndpoints(dp);
+ break;
+ }
+ }
+ }
+
mRecentsAnimationWrapper.setController(controller, apps);
setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
}
public void onGestureStarted() {
+ if (mLauncher != null) {
+ notifyGestureStarted();
+ }
+
setStateOnUiThread(STATE_GESTURE_STARTED);
mGestureStarted = true;
}
+ /**
+ * Notifies the launcher that the swipe gesture has started. This can be called multiple times
+ * on both background and UI threads
+ */
+ private void notifyGestureStarted() {
+ mLauncher.onQuickstepGestureStarted(mWasLauncherAlreadyVisible);
+ }
+
@WorkerThread
public void onGestureEnded(float endVelocity) {
Resources res = mContext.getResources();
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 2227bfd..950c7f7 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -217,7 +217,7 @@
return new DeviceProfile(context, inv, size, size, widthPx, heightPx, isLandscape);
}
- DeviceProfile getMultiWindowProfile(Context context, Point mwSize) {
+ public DeviceProfile getMultiWindowProfile(Context context, Point mwSize) {
// We take the minimum sizes of this profile and it's multi-window variant to ensure that
// the system decor is always excluded.
mwSize.set(Math.min(availableWidthPx, mwSize.x), Math.min(availableHeightPx, mwSize.y));
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 5da4944..4d820bc 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -150,7 +150,6 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
-import java.util.concurrent.Executor;
/**
* Default launcher application.
@@ -1166,7 +1165,7 @@
public void updateIconBadges(final Set<PackageUserKey> updatedBadges) {
mWorkspace.updateIconBadges(updatedBadges);
- mAppsView.updateIconBadges(updatedBadges);
+ mAppsView.getAppsStore().updateIconBadges(updatedBadges);
PopupContainerWithArrow popup = PopupContainerWithArrow.getOpen(Launcher.this);
if (popup != null) {
@@ -1193,6 +1192,12 @@
}
}
+ public void onQuickstepGestureStarted(boolean isVisible) {
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onQuickstepGestureStarted(isVisible);
+ }
+ }
+
public AllAppsTransitionController getAllAppsController() {
return mAllAppsController;
}
@@ -2521,6 +2526,11 @@
mPendingExecutor.markCompleted();
}
mPendingExecutor = executor;
+ if (!isInState(ALL_APPS)) {
+ mAppsView.getAppsStore().setDeferUpdates(true);
+ mPendingExecutor.execute(() -> mAppsView.getAppsStore().setDeferUpdates(false));
+ }
+
executor.attachTo(this);
}
@@ -2582,30 +2592,14 @@
* Implementation of the method from LauncherModel.Callbacks.
*/
public void bindAllApplications(ArrayList<AppInfo> apps) {
- if (mAppsView != null) {
- Executor pendingExecutor = getPendingExecutor();
- if (pendingExecutor != null && !isInState(ALL_APPS)) {
- // Wait until the fade in animation has finished before setting all apps list.
- pendingExecutor.execute(() -> bindAllApplications(apps));
- return;
- }
+ mAppsView.getAppsStore().setApps(apps);
- mAppsView.setApps(apps);
- }
if (mLauncherCallbacks != null) {
mLauncherCallbacks.bindAllApplications(apps);
}
}
/**
- * Returns an Executor that will run after the launcher is first drawn (including after the
- * initial fade in animation). Returns null if the first draw has already occurred.
- */
- public @Nullable Executor getPendingExecutor() {
- return mPendingExecutor != null && mPendingExecutor.canQueue() ? mPendingExecutor : null;
- }
-
- /**
* Copies LauncherModel's map of activities to shortcut ids to Launcher's. This is necessary
* because LauncherModel's map is updated in the background, while Launcher runs on the UI.
*/
@@ -2621,16 +2615,12 @@
*/
@Override
public void bindAppsAddedOrUpdated(ArrayList<AppInfo> apps) {
- if (mAppsView != null) {
- mAppsView.addOrUpdateApps(apps);
- }
+ mAppsView.getAppsStore().addOrUpdateApps(apps);
}
@Override
public void bindPromiseAppProgressUpdated(PromiseAppInfo app) {
- if (mAppsView != null) {
- mAppsView.updatePromiseAppProgress(app);
- }
+ mAppsView.getAppsStore().updatePromiseAppProgress(app);
}
@Override
@@ -2676,10 +2666,7 @@
@Override
public void bindAppInfosRemoved(final ArrayList<AppInfo> appInfos) {
- // Update AllApps
- if (mAppsView != null) {
- mAppsView.removeApps(appInfos);
- }
+ mAppsView.getAppsStore().removeApps(appInfos);
}
@Override
diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java
index 914d9eb..ed7bf3d 100644
--- a/src/com/android/launcher3/LauncherCallbacks.java
+++ b/src/com/android/launcher3/LauncherCallbacks.java
@@ -71,4 +71,12 @@
* Extensions points for adding / replacing some other aspects of the Launcher experience.
*/
boolean hasSettings();
+
+ /**
+ * Called when launcher integrated quickstep and some quickstep gesture started. It can be
+ * called multiple times for a single gesture an UI or background thread.
+ *
+ * @param isVisible if Launcher was visible when the gesture started.
+ */
+ void onQuickstepGestureStarted(boolean isVisible);
}
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index de08eb6..d4277db 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -116,6 +116,8 @@
mAH = new AdapterHolder[2];
mAH[AdapterHolder.MAIN] = new AdapterHolder(false /* isWork */);
mAH[AdapterHolder.WORK] = new AdapterHolder(true /* isWork */);
+
+ mAllAppsStore.addUpdateListener(this::onAppsUpdated);
}
@Override
@@ -150,43 +152,25 @@
}
}
+ private void onAppsUpdated() {
+ if (FeatureFlags.ALL_APPS_TABS_ENABLED) {
+ boolean hasWorkApps = false;
+ for (AppInfo app : mAllAppsStore.getApps()) {
+ if (mWorkMatcher.matches(app, null)) {
+ hasWorkApps = true;
+ break;
+ }
+ }
+ rebindAdapters(hasWorkApps);
+ }
+ }
+
@Override
public void setPressedIcon(BubbleTextView icon, Bitmap background) {
mTouchFeedbackView.setPressedIcon(icon, background);
}
/**
- * Sets the current set of apps.
- */
- public void setApps(List<AppInfo> apps) {
- boolean hasWorkProfileApp = hasWorkProfileApp(apps);
- rebindAdapters(hasWorkProfileApp);
- mAllAppsStore.setApps(apps);
- }
-
- /**
- * Adds or updates existing apps in the list
- */
- public void addOrUpdateApps(List<AppInfo> apps) {
- mAllAppsStore.addOrUpdateApps(apps);
- }
-
- /**
- * Removes some apps from the list.
- */
- public void removeApps(List<AppInfo> apps) {
- mAllAppsStore.removeApps(apps);
- }
-
- public void updatePromiseAppProgress(PromiseAppInfo app) {
- mAllAppsStore.updateAllIcons((child) -> {
- if (child.getTag() == app) {
- child.applyProgressLevel(app.level);
- }
- });
- }
-
- /**
* Returns whether the view itself will handle the touch event or not.
*/
public boolean shouldContainerScroll(MotionEvent ev) {
@@ -324,18 +308,6 @@
InsettableFrameLayout.dispatchInsets(this, insets);
}
- public void updateIconBadges(Set<PackageUserKey> updatedBadges) {
- PackageUserKey tempKey = new PackageUserKey(null, null);
- mAllAppsStore.updateAllIcons((child) -> {
- if (child.getTag() instanceof ItemInfo) {
- ItemInfo info = (ItemInfo) child.getTag();
- if (tempKey.updateFromItemInfo(info) && updatedBadges.contains(tempKey)) {
- child.applyBadgeState(info, true /* animate */);
- }
- }
- });
- }
-
public SpringAnimationHandler getSpringAnimationHandler() {
return mUsingTabs ? null : mAH[AdapterHolder.MAIN].animationHandler;
}
@@ -371,17 +343,6 @@
applyTouchDelegate();
}
- private boolean hasWorkProfileApp(List<AppInfo> apps) {
- if (FeatureFlags.ALL_APPS_TABS_ENABLED) {
- for (AppInfo app : apps) {
- if (mWorkMatcher.matches(app, null)) {
- return true;
- }
- }
- }
- return false;
- }
-
private void replaceRVContainer(boolean showTabs) {
for (int i = 0; i < mAH.length; i++) {
if (mAH[i].recyclerView != null) {
diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java
index 846b6a9..dc34892 100644
--- a/src/com/android/launcher3/allapps/AllAppsStore.java
+++ b/src/com/android/launcher3/allapps/AllAppsStore.java
@@ -20,22 +20,30 @@
import com.android.launcher3.AppInfo;
import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.PromiseAppInfo;
import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.PackageUserKey;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
+import java.util.Set;
/**
* A utility class to maintain the collection of all apps.
*/
public class AllAppsStore {
+ private PackageUserKey mTempKey = new PackageUserKey(null, null);
private final HashMap<ComponentKey, AppInfo> mComponentToAppMap = new HashMap<>();
private final List<OnUpdateListener> mUpdateListeners = new ArrayList<>();
private final ArrayList<ViewGroup> mIconContainers = new ArrayList<>();
+ private boolean mDeferUpdates = false;
+ private boolean mUpdatePending = false;
+
public Collection<AppInfo> getApps() {
return mComponentToAppMap.values();
}
@@ -52,6 +60,17 @@
return mComponentToAppMap.get(key);
}
+ public void setDeferUpdates(boolean deferUpdates) {
+ if (mDeferUpdates != deferUpdates) {
+ mDeferUpdates = deferUpdates;
+
+ if (!mDeferUpdates && mUpdatePending) {
+ notifyUpdate();
+ mUpdatePending = false;
+ }
+ }
+ }
+
/**
* Adds or updates existing apps in the list
*/
@@ -74,6 +93,10 @@
private void notifyUpdate() {
+ if (mDeferUpdates) {
+ mUpdatePending = true;
+ return;
+ }
int count = mUpdateListeners.size();
for (int i = 0; i < count; i++) {
mUpdateListeners.get(i).onAppsUpdated();
@@ -98,7 +121,26 @@
mIconContainers.remove(container);
}
- public void updateAllIcons(IconAction action) {
+ public void updateIconBadges(Set<PackageUserKey> updatedBadges) {
+ updateAllIcons((child) -> {
+ if (child.getTag() instanceof ItemInfo) {
+ ItemInfo info = (ItemInfo) child.getTag();
+ if (mTempKey.updateFromItemInfo(info) && updatedBadges.contains(mTempKey)) {
+ child.applyBadgeState(info, true /* animate */);
+ }
+ }
+ });
+ }
+
+ public void updatePromiseAppProgress(PromiseAppInfo app) {
+ updateAllIcons((child) -> {
+ if (child.getTag() == app) {
+ child.applyProgressLevel(app.level);
+ }
+ });
+ }
+
+ private void updateAllIcons(IconAction action) {
for (int i = mIconContainers.size() - 1; i >= 0; i--) {
ViewGroup parent = mIconContainers.get(i);
int childCount = parent.getChildCount();
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index a32f6b1..1cf407e 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -159,6 +159,10 @@
} else if (action == MotionEvent.ACTION_DOWN) {
mLauncher.finishAutoCancelActionMode();
}
+ return findActiveController(ev);
+ }
+
+ private boolean findActiveController(MotionEvent ev) {
mActiveController = null;
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mLauncher);
@@ -285,8 +289,10 @@
if (mActiveController != null) {
return mActiveController.onControllerTouchEvent(ev);
+ } else {
+ // In case no child view handled the touch event, we may not get onIntercept anymore
+ return findActiveController(ev);
}
- return false;
}
/**