Revert "Unifying various model update callbacks into one"
Revert submission 31445615-model-callbacks
Reason for revert: <Droidmonitor crested revert due to b/393222548. Will be verified through ABTD for stanadard investigation.>
Reverted changes: /q/submissionid:31445615-model-callbacks
Change-Id: If6893a125756e5abfbb215af377576429bb1c91b
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 6815f97..f905c5f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -25,6 +25,7 @@
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
@@ -38,9 +39,9 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.function.Predicate;
/**
@@ -113,9 +114,15 @@
return modified;
}
+
@Override
- public void bindItemsUpdated(Set<ItemInfo> updates) {
- updateContainerItems(updates, mContext);
+ public void bindWorkspaceItemsChanged(List<WorkspaceItemInfo> updated) {
+ updateWorkspaceItems(updated, mContext);
+ }
+
+ @Override
+ public void bindRestoreItemsChange(HashSet<ItemInfo> updates) {
+ updateRestoreItems(updates, mContext);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
index 9b7bb1c..a85e5e0 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
@@ -214,7 +214,7 @@
boolean animate = shouldAnimateIconChange(info);
Drawable oldIcon = getIcon();
int oldPlateColor = mPlateColor.currentColor;
- applyFromWorkspaceItem(info);
+ applyFromWorkspaceItem(info, null);
setContentDescription(
mIsPinned ? info.contentDescription :
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index d3684b2..315096c 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -29,7 +29,6 @@
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_INCREMENTAL_DOWNLOAD_ACTIVE;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
-import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -64,7 +63,6 @@
import android.widget.TextView;
import androidx.annotation.DrawableRes;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.annotation.VisibleForTesting;
@@ -368,6 +366,11 @@
mDotScaleAnim.start();
}
+ @UiThread
+ public void applyFromWorkspaceItem(WorkspaceItemInfo info) {
+ applyFromWorkspaceItem(info, null);
+ }
+
@Override
public void setAccessibilityDelegate(AccessibilityDelegate delegate) {
if (delegate instanceof BaseAccessibilityDelegate) {
@@ -381,10 +384,10 @@
}
@UiThread
- public void applyFromWorkspaceItem(WorkspaceItemInfo info) {
+ public void applyFromWorkspaceItem(WorkspaceItemInfo info, PreloadIconDrawable icon) {
applyIconAndLabel(info);
setItemInfo(info);
-
+ applyLoadingState(icon);
applyDotState(info, false /* animate */);
setDownloadStateContentDescription(info, info.getProgressLevel());
}
@@ -392,11 +395,17 @@
@UiThread
public void applyFromApplicationInfo(AppInfo info) {
applyIconAndLabel(info);
+
+ // We don't need to check the info since it's not a WorkspaceItemInfo
setItemInfo(info);
+
// Verify high res immediately
verifyHighRes();
+ if ((info.runtimeStatusFlags & ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) {
+ applyProgressLevel();
+ }
applyDotState(info, false /* animate */);
setDownloadStateContentDescription(info, info.getProgressLevel());
}
@@ -440,50 +449,6 @@
@VisibleForTesting
@UiThread
public void applyIconAndLabel(ItemInfoWithIcon info) {
- FastBitmapDrawable oldIcon = mIcon;
- if (!canReuseIcon(info)) {
- setNonPendingIcon(info);
- }
- applyLabel(info);
- maybeApplyProgressLevel(info, oldIcon);
- }
-
- /**
- * Check if we can reuse icon so that any animation is preserved
- */
- private boolean canReuseIcon(ItemInfoWithIcon info) {
- return mIcon instanceof PreloadIconDrawable p
- && p.hasNotCompleted() && p.isSameInfo(info.bitmap);
- }
-
- /**
- * Apply progress level to the icon if necessary
- */
- private void maybeApplyProgressLevel(ItemInfoWithIcon info, FastBitmapDrawable oldIcon) {
- if (!shouldApplyProgressLevel(info, oldIcon)) {
- return;
- }
- PreloadIconDrawable pendingIcon = applyProgressLevel(info);
- boolean isNoLongerPending = info instanceof WorkspaceItemInfo wii
- ? !wii.hasPromiseIconUi() : !info.isArchived();
- if (isNoLongerPending && info.getProgressLevel() == 100 && pendingIcon != null) {
- pendingIcon.maybePerformFinishedAnimation(
- (oldIcon instanceof PreloadIconDrawable p) ? p : pendingIcon,
- () -> setNonPendingIcon(
- (getTag() instanceof ItemInfoWithIcon iiwi) ? iiwi : info));
- }
- }
-
- /**
- * Check if progress level should be applied to the icon
- */
- private boolean shouldApplyProgressLevel(ItemInfoWithIcon info, FastBitmapDrawable oldIcon) {
- return (info.runtimeStatusFlags & FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0
- || (info instanceof WorkspaceItemInfo wii && wii.hasPromiseIconUi())
- || (oldIcon instanceof PreloadIconDrawable p && p.hasNotCompleted());
- }
-
- private void setNonPendingIcon(ItemInfoWithIcon info) {
ThemeManager themeManager = ThemeManager.INSTANCE.get(getContext());
int flags = (shouldUseTheme()
&& themeManager.isMonoThemeEnabled()) ? FLAG_THEMED : 0;
@@ -498,6 +463,7 @@
mDotParams.appColor = iconDrawable.getIconColor();
mDotParams.dotColor = Themes.getAttrColor(getContext(), R.attr.notificationDotColor);
setIcon(iconDrawable);
+ applyLabel(info);
}
protected boolean shouldUseTheme() {
@@ -1104,10 +1070,38 @@
mLongPressHelper.cancelLongPress();
}
+ /**
+ * Applies the loading progress value to the progress bar.
+ *
+ * If this app is installing, the progress bar will be updated with the installation progress.
+ * If this app is installed and downloading incrementally, the progress bar will be updated
+ * with the total download progress.
+ */
+ public void applyLoadingState(PreloadIconDrawable icon) {
+ if (getTag() instanceof ItemInfoWithIcon) {
+ WorkspaceItemInfo info = (WorkspaceItemInfo) getTag();
+ if ((info.runtimeStatusFlags & FLAG_INCREMENTAL_DOWNLOAD_ACTIVE) != 0
+ || info.hasPromiseIconUi()
+ || (info.runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) != 0
+ || (icon != null)) {
+ updateProgressBarUi(info.getProgressLevel() == 100 ? icon : null);
+ }
+ }
+ }
+
+ private void updateProgressBarUi(PreloadIconDrawable oldIcon) {
+ FastBitmapDrawable originalIcon = mIcon;
+ PreloadIconDrawable preloadDrawable = applyProgressLevel();
+ if (preloadDrawable != null && oldIcon != null) {
+ preloadDrawable.maybePerformFinishedAnimation(oldIcon, () -> setIcon(originalIcon));
+ }
+ }
+
/** Applies the given progress level to the this icon's progress bar. */
@Nullable
- private PreloadIconDrawable applyProgressLevel(ItemInfoWithIcon info) {
- if (info.isInactiveArchive()) {
+ public PreloadIconDrawable applyProgressLevel() {
+ if (!(getTag() instanceof ItemInfoWithIcon info)
+ || ((ItemInfoWithIcon) getTag()).isInactiveArchive()) {
return null;
}
@@ -1121,16 +1115,23 @@
setContentDescription(getContext()
.getString(R.string.app_waiting_download_title, info.title));
}
- PreloadIconDrawable pid;
- if (mIcon instanceof PreloadIconDrawable p) {
- pid = p;
- pid.setLevel(progressLevel);
- pid.setIsDisabled(isIconDisabled(info));
- } else {
- pid = makePreloadIcon(info);
- setIcon(pid);
+ if (mIcon != null) {
+ PreloadIconDrawable preloadIconDrawable;
+ if (mIcon instanceof PreloadIconDrawable) {
+ preloadIconDrawable = (PreloadIconDrawable) mIcon;
+ preloadIconDrawable.setLevel(progressLevel);
+ preloadIconDrawable.setIsDisabled(isIconDisabled(info));
+ } else {
+ preloadIconDrawable = makePreloadIcon();
+ setIcon(preloadIconDrawable);
+ if (info.isArchived() && Flags.useNewIconForArchivedApps()) {
+ // reapply text without cloud icon as soon as unarchiving is triggered
+ applyLabel(info);
+ }
+ }
+ return preloadIconDrawable;
}
- return pid;
+ return null;
}
/**
@@ -1139,11 +1140,11 @@
*/
@Nullable
public PreloadIconDrawable makePreloadIcon() {
- return getTag() instanceof ItemInfoWithIcon info ? makePreloadIcon(info) : null;
- }
+ if (!(getTag() instanceof ItemInfoWithIcon)) {
+ return null;
+ }
- @NonNull
- private PreloadIconDrawable makePreloadIcon(ItemInfoWithIcon info) {
+ ItemInfoWithIcon info = (ItemInfoWithIcon) getTag();
int progressLevel = info.getProgressLevel();
final PreloadIconDrawable preloadDrawable = newPendingIcon(getContext(), info);
@@ -1162,7 +1163,7 @@
public void applyDotState(ItemInfo itemInfo, boolean animate) {
- if (mIcon != null) {
+ if (mIcon instanceof FastBitmapDrawable) {
boolean wasDotted = mDotInfo != null;
mDotInfo = mActivity.getDotInfoForItem(itemInfo);
boolean isDotted = mDotInfo != null;
@@ -1211,7 +1212,7 @@
setContentDescription(getContext().getString(
R.string.app_archived_title, info.title));
}
- } else if ((info.runtimeStatusFlags & FLAG_SHOW_DOWNLOAD_PROGRESS_MASK)
+ } else if ((info.runtimeStatusFlags & ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK)
!= 0) {
String percentageString = NumberFormat.getPercentInstance()
.format(progressLevel * 0.01);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 647d2ad..7df4014 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -277,11 +277,11 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
-import java.util.Set;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
@@ -2598,12 +2598,25 @@
mModelCallbacks.bindIncrementalDownloadProgressUpdated(app);
}
+ @Override
+ public void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets) {
+ mModelCallbacks.bindWidgetsRestored(widgets);
+ }
+
/**
* See {@code LauncherBindingDelegate}
*/
@Override
- public void bindItemsUpdated(Set<ItemInfo> updates) {
- mModelCallbacks.bindItemsUpdated(updates);
+ public void bindWorkspaceItemsChanged(List<WorkspaceItemInfo> updated) {
+ mModelCallbacks.bindWorkspaceItemsChanged(updated);
+ }
+
+ /**
+ * See {@code LauncherBindingDelegate}
+ */
+ @Override
+ public void bindRestoreItemsChange(HashSet<ItemInfo> updates) {
+ mModelCallbacks.bindRestoreItemsChange(updates);
}
/**
diff --git a/src/com/android/launcher3/ModelCallbacks.kt b/src/com/android/launcher3/ModelCallbacks.kt
index 5338fb4..5d32525 100644
--- a/src/com/android/launcher3/ModelCallbacks.kt
+++ b/src/com/android/launcher3/ModelCallbacks.kt
@@ -17,6 +17,8 @@
import com.android.launcher3.model.StringCache
import com.android.launcher3.model.data.AppInfo
import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.LauncherAppWidgetInfo
+import com.android.launcher3.model.data.WorkspaceItemInfo
import com.android.launcher3.popup.PopupContainerWithArrow
import com.android.launcher3.util.ComponentKey
import com.android.launcher3.util.IntArray as LIntArray
@@ -213,13 +215,29 @@
launcher.appsView.appsStore.updateProgressBar(app)
}
+ override fun bindWidgetsRestored(widgets: ArrayList<LauncherAppWidgetInfo?>?) {
+ launcher.workspace.widgetsRestored(widgets)
+ }
+
+ /**
+ * Some shortcuts were updated in the background. Implementation of the method from
+ * LauncherModel.Callbacks.
+ *
+ * @param updated list of shortcuts which have changed.
+ */
+ override fun bindWorkspaceItemsChanged(updated: List<WorkspaceItemInfo?>) {
+ if (updated.isNotEmpty()) {
+ launcher.workspace.updateWorkspaceItems(updated, launcher)
+ PopupContainerWithArrow.dismissInvalidPopup(launcher)
+ }
+ }
+
/**
* Update the state of a package, typically related to install state. Implementation of the
* method from LauncherModel.Callbacks.
*/
- override fun bindItemsUpdated(updates: Set<ItemInfo>) {
- launcher.workspace.updateContainerItems(updates, launcher)
- PopupContainerWithArrow.dismissInvalidPopup(launcher)
+ override fun bindRestoreItemsChange(updates: HashSet<ItemInfo?>?) {
+ launcher.workspace.updateRestoreItems(updates, launcher)
}
/**
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 7d82179..86c49d0 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -53,6 +53,8 @@
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
@@ -123,9 +125,13 @@
import com.android.launcher3.util.Thunk;
import com.android.launcher3.util.WallpaperOffsetInterpolator;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
+import com.android.launcher3.widget.LauncherWidgetHolder;
+import com.android.launcher3.widget.LauncherWidgetHolder.ProviderChangedListener;
import com.android.launcher3.widget.NavigableAppWidgetHostView;
import com.android.launcher3.widget.PendingAddShortcutInfo;
import com.android.launcher3.widget.PendingAddWidgetInfo;
+import com.android.launcher3.widget.PendingAppWidgetHostView;
+import com.android.launcher3.widget.WidgetManagerHelper;
import com.android.launcher3.widget.util.WidgetSizes;
import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayCallbacks;
import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayTouchProxy;
@@ -658,6 +664,9 @@
bindAndInitFirstWorkspaceScreen();
}
+ // Remove any deferred refresh callbacks
+ mLauncher.mHandler.removeCallbacksAndMessages(DeferredWidgetRefresh.class);
+
// Re-enable the layout transitions
enableLayoutTransitions();
}
@@ -3456,6 +3465,43 @@
removeItemsByMatcher(matcher);
}
+ public void widgetsRestored(final ArrayList<LauncherAppWidgetInfo> changedInfo) {
+ if (!changedInfo.isEmpty()) {
+ DeferredWidgetRefresh widgetRefresh = new DeferredWidgetRefresh(changedInfo,
+ mLauncher.getAppWidgetHolder());
+
+ LauncherAppWidgetInfo item = changedInfo.get(0);
+ final AppWidgetProviderInfo widgetInfo;
+ WidgetManagerHelper widgetHelper = new WidgetManagerHelper(getContext());
+ if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
+ widgetInfo = widgetHelper.findProvider(item.providerName, item.user);
+ } else {
+ widgetInfo = widgetHelper.getLauncherAppWidgetInfo(item.appWidgetId,
+ item.getTargetComponent());
+ }
+
+ if (widgetInfo != null) {
+ // Re-inflate the widgets which have changed status
+ widgetRefresh.run();
+ } else {
+ // widgetRefresh will automatically run when the packages are updated.
+ // For now just update the progress bars
+ mapOverItems(new ItemOperator() {
+ @Override
+ public boolean evaluate(ItemInfo info, View view) {
+ if (view instanceof PendingAppWidgetHostView
+ && changedInfo.contains(info)) {
+ ((LauncherAppWidgetInfo) info).installProgress = 100;
+ ((PendingAppWidgetHostView) view).applyState();
+ }
+ // process all the shortcuts
+ return false;
+ }
+ });
+ }
+ }
+ }
+
public boolean isOverlayShown() {
return mOverlayShown;
}
@@ -3562,6 +3608,62 @@
return mLauncher.getCellPosMapper();
}
+ /**
+ * Used as a workaround to ensure that the AppWidgetService receives the
+ * PACKAGE_ADDED broadcast before updating widgets.
+ */
+ private class DeferredWidgetRefresh implements Runnable, ProviderChangedListener {
+ private final ArrayList<LauncherAppWidgetInfo> mInfos;
+ private final LauncherWidgetHolder mWidgetHolder;
+ private final Handler mHandler;
+
+ private boolean mRefreshPending;
+
+ DeferredWidgetRefresh(ArrayList<LauncherAppWidgetInfo> infos,
+ LauncherWidgetHolder holder) {
+ mInfos = infos;
+ mWidgetHolder = holder;
+ mHandler = mLauncher.mHandler;
+ mRefreshPending = true;
+
+ mWidgetHolder.addProviderChangeListener(this);
+ // Force refresh after 10 seconds, if we don't get the provider changed event.
+ // This could happen when the provider is no longer available in the app.
+ Message msg = Message.obtain(mHandler, this);
+ msg.obj = DeferredWidgetRefresh.class;
+ mHandler.sendMessageDelayed(msg, 10000);
+ }
+
+ @Override
+ public void run() {
+ mWidgetHolder.removeProviderChangeListener(this);
+ mHandler.removeCallbacks(this);
+
+ if (!mRefreshPending) {
+ return;
+ }
+
+ mRefreshPending = false;
+
+ ArrayList<PendingAppWidgetHostView> views = new ArrayList<>(mInfos.size());
+ mapOverItems((info, view) -> {
+ if (view instanceof PendingAppWidgetHostView && mInfos.contains(info)) {
+ views.add((PendingAppWidgetHostView) view);
+ }
+ // process all children
+ return false;
+ });
+ for (PendingAppWidgetHostView view : views) {
+ view.reInflate();
+ }
+ }
+
+ @Override
+ public void notifyWidgetProvidersChanged() {
+ run();
+ }
+ }
+
private class StateTransitionListener extends AnimatorListenerAdapter
implements AnimatorUpdateListener {
diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java
index d5a4022..9afe06c 100644
--- a/src/com/android/launcher3/allapps/AllAppsStore.java
+++ b/src/com/android/launcher3/allapps/AllAppsStore.java
@@ -17,6 +17,7 @@
import static com.android.launcher3.model.data.AppInfo.COMPONENT_KEY_COMPARATOR;
import static com.android.launcher3.model.data.AppInfo.EMPTY_ARRAY;
+import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK;
import android.content.Context;
import android.os.UserHandle;
@@ -228,7 +229,11 @@
public void updateProgressBar(AppInfo app) {
updateAllIcons((child) -> {
if (child.getTag() == app) {
- child.applyFromApplicationInfo(app);
+ if ((app.runtimeStatusFlags & FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) == 0) {
+ child.applyFromApplicationInfo(app);
+ } else {
+ child.applyProgressLevel();
+ }
}
});
}
diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
index f189182..3464e9b 100644
--- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java
+++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
@@ -24,6 +24,7 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
+import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
@@ -32,14 +33,12 @@
import android.graphics.Rect;
import android.util.Property;
-import androidx.annotation.VisibleForTesting;
import androidx.core.graphics.ColorUtils;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.anim.AnimatorListeners;
-import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.util.Themes;
@@ -64,6 +63,8 @@
private static final int DEFAULT_PATH_SIZE = 100;
private static final int MAX_PAINT_ALPHA = 255;
+ private static final int TRACK_ALPHA = (int) (0.27f * MAX_PAINT_ALPHA);
+ private static final int DISABLED_ICON_ALPHA = (int) (0.6f * MAX_PAINT_ALPHA);
private static final long DURATION_SCALE = 500;
private static final long SCALE_AND_ALPHA_ANIM_DURATION = 500;
@@ -283,25 +284,20 @@
(long) ((finalProgress - mInternalStateProgress) * DURATION_SCALE));
mCurrentAnim.setInterpolator(LINEAR);
if (isFinish) {
+ if (onFinishCallback != null) {
+ mCurrentAnim.addListener(AnimatorListeners.forEndCallback(onFinishCallback));
+ }
mCurrentAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mRanFinishAnimation = true;
}
});
- if (onFinishCallback != null) {
- mCurrentAnim.addListener(AnimatorListeners.forEndCallback(onFinishCallback));
- }
}
mCurrentAnim.start();
}
}
- @VisibleForTesting
- public ObjectAnimator getActiveAnimation() {
- return mCurrentAnim;
- }
-
/**
* Sets the internal progress and updates the UI accordingly
* for progress <= 0:
@@ -362,7 +358,8 @@
@Override
public FastBitmapConstantState newConstantState() {
return new PreloadIconConstantState(
- mBitmapInfo,
+ mBitmap,
+ mIconColor,
mItem,
mIndicatorColor,
new int[] {mSystemAccentColor, mSystemBackgroundColor},
@@ -380,13 +377,14 @@
private final Path mShapePath;
public PreloadIconConstantState(
- BitmapInfo bitmapInfo,
+ Bitmap bitmap,
+ int iconColor,
ItemInfoWithIcon info,
int indicatorColor,
int[] preloadColors,
boolean isDarkMode,
Path shapePath) {
- super(bitmapInfo);
+ super(bitmap, iconColor);
mInfo = info;
mIndicatorColor = indicatorColor;
mPreloadColors = preloadColors;
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index ddc775d..a04cbfb 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -49,6 +49,7 @@
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.CollectionInfo;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.shortcuts.ShortcutKey;
@@ -69,6 +70,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -417,9 +419,9 @@
* Binds updated incremental download progress
*/
default void bindIncrementalDownloadProgressUpdated(AppInfo app) { }
-
- /** Called when a runtime property of the ItemInfo is updated due to some system event */
- default void bindItemsUpdated(Set<ItemInfo> updates) { }
+ default void bindWorkspaceItemsChanged(List<WorkspaceItemInfo> updated) { }
+ default void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets) { }
+ default void bindRestoreItemsChange(HashSet<ItemInfo> updates) { }
default void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) { }
/**
diff --git a/src/com/android/launcher3/model/CacheDataUpdatedTask.java b/src/com/android/launcher3/model/CacheDataUpdatedTask.java
index 48934e2..b544b91 100644
--- a/src/com/android/launcher3/model/CacheDataUpdatedTask.java
+++ b/src/com/android/launcher3/model/CacheDataUpdatedTask.java
@@ -15,9 +15,6 @@
*/
package com.android.launcher3.model;
-import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
-import static com.android.launcher3.model.ModelUtils.WIDGET_FILTER;
-
import android.content.ComponentName;
import android.os.UserHandle;
@@ -26,8 +23,6 @@
import com.android.launcher3.LauncherModel.ModelUpdateTask;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.icons.IconCache;
-import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import java.util.ArrayList;
@@ -60,7 +55,7 @@
public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
@NonNull AllAppsList apps) {
IconCache iconCache = taskController.getApp().getIconCache();
- ArrayList<ItemInfo> updatedItems = new ArrayList<>();
+ ArrayList<WorkspaceItemInfo> updatedShortcuts = new ArrayList<>();
synchronized (dataModel) {
dataModel.forAllWorkspaceItemInfos(mUser, si -> {
@@ -69,25 +64,12 @@
&& isValidShortcut(si) && cn != null
&& mPackages.contains(cn.getPackageName())) {
iconCache.getTitleAndIcon(si, si.getMatchingLookupFlag());
- updatedItems.add(si);
+ updatedShortcuts.add(si);
}
});
-
- dataModel.itemsIdMap.stream()
- .filter(WIDGET_FILTER)
- .filter(item -> mUser.equals(item.user))
- .map(item -> (LauncherAppWidgetInfo) item)
- .filter(widget -> mPackages.contains(widget.providerName.getPackageName())
- && widget.pendingItemInfo != null)
- .forEach(widget -> {
- iconCache.getTitleAndIconForApp(
- widget.pendingItemInfo, DEFAULT_LOOKUP_FLAG);
- updatedItems.add(widget);
- });
-
apps.updateIconsAndLabels(mPackages, mUser);
}
- taskController.bindUpdatedWorkspaceItems(updatedItems);
+ taskController.bindUpdatedWorkspaceItems(updatedShortcuts);
taskController.bindApplicationsIfNeeded();
}
diff --git a/src/com/android/launcher3/model/ModelTaskController.kt b/src/com/android/launcher3/model/ModelTaskController.kt
index 40ea17d..fc53343 100644
--- a/src/com/android/launcher3/model/ModelTaskController.kt
+++ b/src/com/android/launcher3/model/ModelTaskController.kt
@@ -22,6 +22,7 @@
import com.android.launcher3.celllayout.CellPosMapper
import com.android.launcher3.model.BgDataModel.FixedContainerItems
import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.WorkspaceItemInfo
import com.android.launcher3.util.PackageUserKey
import com.android.launcher3.widget.model.WidgetsListBaseEntriesBuilder
import java.util.Objects
@@ -50,17 +51,18 @@
*/
fun getModelWriter() = model.getWriter(false /* verifyChanges */, CellPosMapper.DEFAULT, null)
- fun bindUpdatedWorkspaceItems(allUpdates: Collection<ItemInfo>) {
+ fun bindUpdatedWorkspaceItems(allUpdates: List<WorkspaceItemInfo>) {
// Bind workspace items
- val workspaceUpdates = allUpdates.filter { it.id != ItemInfo.NO_ID }.toSet()
+ val workspaceUpdates =
+ allUpdates.stream().filter { info -> info.id != ItemInfo.NO_ID }.toList()
if (workspaceUpdates.isNotEmpty()) {
- scheduleCallbackTask { it.bindItemsUpdated(workspaceUpdates) }
+ scheduleCallbackTask { it.bindWorkspaceItemsChanged(workspaceUpdates) }
}
// Bind extra items if any
allUpdates
.stream()
- .mapToInt { it.container }
+ .mapToInt { info: WorkspaceItemInfo -> info.container }
.distinct()
.mapToObj { dataModel.extraItems.get(it) }
.filter { Objects.nonNull(it) }
diff --git a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
index a216042..4103937 100644
--- a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
+++ b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
@@ -99,7 +99,8 @@
});
if (!updates.isEmpty()) {
- taskController.bindUpdatedWorkspaceItems(updates);
+ taskController.scheduleCallbackTask(
+ callbacks -> callbacks.bindRestoreItemsChange(updates));
}
}
}
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 6bef292..1153f48 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -214,7 +214,8 @@
// Update shortcut infos
if (mOp == OP_ADD || flagOp != FlagOp.NO_OP) {
- final ArrayList<ItemInfo> updatedWorkspaceItems = new ArrayList<>();
+ final ArrayList<WorkspaceItemInfo> updatedWorkspaceItems = new ArrayList<>();
+ final ArrayList<LauncherAppWidgetInfo> widgets = new ArrayList<>();
// For system apps, package manager send OP_UPDATE when an app is enabled.
final boolean isNewApkAvailable = mOp == OP_ADD || mOp == OP_UPDATE;
@@ -363,8 +364,8 @@
// if the widget has a config activity. In case there is no config
// activity, it will be marked as 'restored' during bind.
widgetInfo.restoreStatus |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
- widgetInfo.installProgress = 100;
- updatedWorkspaceItems.add(widgetInfo);
+
+ widgets.add(widgetInfo);
taskController.getModelWriter().updateItemInDatabase(widgetInfo);
});
}
@@ -376,6 +377,10 @@
"removing shortcuts with invalid target components."
+ " ids=" + removedShortcuts);
}
+
+ if (!widgets.isEmpty()) {
+ taskController.scheduleCallbackTask(c -> c.bindWidgetsRestored(widgets));
+ }
}
final HashSet<String> removedPackages = new HashSet<>();
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index 381d17a..78709b8 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -228,9 +228,10 @@
private static void onClickPendingAppItem(View v, Launcher launcher, String packageName,
boolean downloadStarted) {
ItemInfo item = (ItemInfo) v.getTag();
- CompletableFuture<SessionInfo> siFuture = CompletableFuture.supplyAsync(() ->
- InstallSessionHelper.INSTANCE.get(launcher)
- .getActiveSessionInfo(item.user, packageName),
+ CompletableFuture<SessionInfo> siFuture;
+ siFuture = CompletableFuture.supplyAsync(() ->
+ InstallSessionHelper.INSTANCE.get(launcher)
+ .getActiveSessionInfo(item.user, packageName),
UI_HELPER_EXECUTOR);
Consumer<SessionInfo> marketLaunchAction = sessionInfo -> {
if (sessionInfo != null) {
@@ -244,8 +245,8 @@
}
}
// Fallback to using custom market intent.
- Intent intent = ApiWrapper.INSTANCE.get(launcher).getMarketSearchIntent(
- packageName, item.user);
+ Intent intent = ApiWrapper.INSTANCE.get(launcher).getAppMarketActivityIntent(
+ packageName, Process.myUserHandle());
launcher.startActivitySafely(v, intent, item);
};
@@ -357,7 +358,9 @@
// Check for abandoned promise
if ((v instanceof BubbleTextView) && shortcut.hasPromiseIconUi()
&& (!Flags.enableSupportForArchiving() || !shortcut.isArchived())) {
- String packageName = shortcut.getTargetPackage();
+ String packageName = shortcut.getIntent().getComponent() != null
+ ? shortcut.getIntent().getComponent().getPackageName()
+ : shortcut.getIntent().getPackage();
if (!TextUtils.isEmpty(packageName)) {
onClickPendingAppItem(
v,
diff --git a/src/com/android/launcher3/util/ApiWrapper.java b/src/com/android/launcher3/util/ApiWrapper.java
index d24d084..467a7ec 100644
--- a/src/com/android/launcher3/util/ApiWrapper.java
+++ b/src/com/android/launcher3/util/ApiWrapper.java
@@ -28,7 +28,6 @@
import android.content.pm.ShortcutInfo;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
-import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArrayMap;
@@ -121,21 +120,6 @@
* Activity).
*/
public Intent getAppMarketActivityIntent(String packageName, UserHandle user) {
- return createMarketIntent(packageName);
- }
-
- /**
- * Returns an intent which can be used to start a search for a package on app market
- */
- public Intent getMarketSearchIntent(String packageName, UserHandle user) {
- // If we are search for the current user, just launch the market directly as the
- // system won't have the installer details either
- return (Process.myUserHandle().equals(user))
- ? createMarketIntent(packageName)
- : getAppMarketActivityIntent(packageName, user);
- }
-
- private static Intent createMarketIntent(String packageName) {
return new Intent(Intent.ACTION_VIEW)
.setData(new Uri.Builder()
.scheme("market")
diff --git a/src/com/android/launcher3/util/LauncherBindableItemsContainer.java b/src/com/android/launcher3/util/LauncherBindableItemsContainer.java
index 20e3eaf..02779ce 100644
--- a/src/com/android/launcher3/util/LauncherBindableItemsContainer.java
+++ b/src/com/android/launcher3/util/LauncherBindableItemsContainer.java
@@ -15,20 +15,24 @@
*/
package com.android.launcher3.util;
+import android.graphics.drawable.Drawable;
import android.view.View;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.apppairs.AppPairIcon;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.graphics.PreloadIconDrawable;
import com.android.launcher3.model.data.AppPairInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.widget.PendingAppWidgetHostView;
-import java.util.Set;
+import java.util.HashSet;
+import java.util.List;
/**
* Interface representing a container which can bind Launcher items with some utility methods
@@ -37,22 +41,27 @@
/**
* Called to update workspace items as a result of
- * {@link com.android.launcher3.model.BgDataModel.Callbacks#bindItemsUpdated(Set)}
+ * {@link com.android.launcher3.model.BgDataModel.Callbacks#bindWorkspaceItemsChanged(List)}
*/
- default void updateContainerItems(Set<ItemInfo> updates, ActivityContext context) {
+ default void updateWorkspaceItems(List<WorkspaceItemInfo> shortcuts, ActivityContext context) {
+ final HashSet<WorkspaceItemInfo> updates = new HashSet<>(shortcuts);
ItemOperator op = (info, v) -> {
- if (v instanceof BubbleTextView shortcut
- && info instanceof WorkspaceItemInfo wii
- && updates.contains(info)) {
- shortcut.applyFromWorkspaceItem(wii);
- } else if (info instanceof FolderInfo && v instanceof FolderIcon folderIcon) {
- folderIcon.updatePreviewItems(updates::contains);
+ 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
+ && oldIcon instanceof PreloadIconDrawable
+ ? (PreloadIconDrawable) oldIcon
+ : null);
+ } else if (info instanceof FolderInfo && v instanceof FolderIcon) {
+ ((FolderIcon) v).updatePreviewItems(updates::contains);
} else if (info instanceof AppPairInfo && v instanceof AppPairIcon appPairIcon) {
appPairIcon.maybeRedrawForWorkspaceUpdate(updates::contains);
- } else if (v instanceof PendingAppWidgetHostView pendingView
- && updates.contains(info)) {
- pendingView.applyState();
- pendingView.postProviderAvailabilityCheck();
}
// Iterate all items
@@ -67,6 +76,35 @@
}
/**
+ * Called to update restored items as a result of
+ * {@link com.android.launcher3.model.BgDataModel.Callbacks#bindRestoreItemsChange(HashSet)}}
+ */
+ default void updateRestoreItems(final HashSet<ItemInfo> updates, ActivityContext context) {
+ ItemOperator op = (info, v) -> {
+ if (info instanceof WorkspaceItemInfo && v instanceof BubbleTextView
+ && updates.contains(info)) {
+ ((BubbleTextView) v).applyLoadingState(null);
+ } 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);
+ } else if (info instanceof AppPairInfo && v instanceof AppPairIcon appPairIcon) {
+ appPairIcon.maybeRedrawForWorkspaceUpdate(updates::contains);
+ }
+ // process all the shortcuts
+ return false;
+ };
+
+ mapOverItems(op);
+ Folder folder = Folder.getOpen(context);
+ if (folder != null) {
+ folder.iterateOverItems(op);
+ }
+ }
+
+ /**
* Map the operator over the shortcuts and widgets.
*
* @param op the operator to map over the shortcuts
diff --git a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
index cd8e457..9c9b80d 100644
--- a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
@@ -21,7 +21,7 @@
import static android.graphics.Paint.FILTER_BITMAP_FLAG;
import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
-import static com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
+import static com.android.launcher3.icons.FastBitmapDrawable.getDisabledColorFilter;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.appwidget.AppWidgetProviderInfo;
@@ -37,9 +37,6 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
@@ -63,10 +60,8 @@
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.PackageItemInfo;
-import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.Themes;
-import com.android.launcher3.widget.LauncherWidgetHolder.ProviderChangedListener;
import java.util.List;
@@ -86,8 +81,6 @@
private final Matrix mMatrix = new Matrix();
private final RectF mPreviewBitmapRect = new RectF();
private final RectF mCanvasRect = new RectF();
- private final Handler mHandler = new Handler(Looper.getMainLooper());
- private final RunnableList mOnDetachCleanup = new RunnableList();
private final LauncherWidgetHolder mWidgetHolder;
private final LauncherAppWidgetProviderInfo mAppwidget;
@@ -97,6 +90,7 @@
private final CharSequence mLabel;
private OnClickListener mClickListener;
+ private SafeCloseable mOnDetachCleanup;
private int mDragFlags;
@@ -216,15 +210,16 @@
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- mOnDetachCleanup.executeAllAndClear();
if ((mAppwidget != null)
&& !mInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)
&& mInfo.restoreStatus != LauncherAppWidgetInfo.RESTORE_COMPLETED) {
// If the widget is not completely restored, but has a valid ID, then listen of
// updates from provider app for potential restore complete.
- SafeCloseable updateCleanup = mWidgetHolder.addOnUpdateListener(
+ if (mOnDetachCleanup != null) {
+ mOnDetachCleanup.close();
+ }
+ mOnDetachCleanup = mWidgetHolder.addOnUpdateListener(
mInfo.appWidgetId, mAppwidget, this::checkIfRestored);
- mOnDetachCleanup.add(updateCleanup::close);
checkIfRestored();
}
}
@@ -232,7 +227,10 @@
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- mOnDetachCleanup.executeAllAndClear();
+ if (mOnDetachCleanup != null) {
+ mOnDetachCleanup.close();
+ mOnDetachCleanup = null;
+ }
}
/**
@@ -297,30 +295,43 @@
mCenterDrawable.setCallback(null);
mCenterDrawable = null;
}
- mDragFlags = FLAG_DRAW_ICON;
+ mDragFlags = 0;
+ if (info.bitmap.icon != null) {
+ mDragFlags = FLAG_DRAW_ICON;
- // The view displays three modes,
- // 1) App icon in the center
- // 2) Preload icon in the center
- // 3) App icon in the center with a setup icon on the top left corner.
- if (mDisabledForSafeMode) {
- FastBitmapDrawable disabledIcon = info.newIcon(getContext());
- disabledIcon.setIsDisabled(true);
- mCenterDrawable = disabledIcon;
- mSettingIconDrawable = null;
- } else if (isReadyForClickSetup()) {
- mCenterDrawable = info.newIcon(getContext());
- mSettingIconDrawable = getResources().getDrawable(R.drawable.ic_setting).mutate();
- updateSettingColor(info.bitmap.color);
+ Drawable widgetCategoryIcon = getWidgetCategoryIcon();
+ // The view displays three modes,
+ // 1) App icon in the center
+ // 2) Preload icon in the center
+ // 3) App icon in the center with a setup icon on the top left corner.
+ if (mDisabledForSafeMode) {
+ if (widgetCategoryIcon == null) {
+ FastBitmapDrawable disabledIcon = info.newIcon(getContext());
+ disabledIcon.setIsDisabled(true);
+ mCenterDrawable = disabledIcon;
+ } else {
+ widgetCategoryIcon.setColorFilter(getDisabledColorFilter());
+ mCenterDrawable = widgetCategoryIcon;
+ }
+ mSettingIconDrawable = null;
+ } else if (isReadyForClickSetup()) {
+ mCenterDrawable = widgetCategoryIcon == null
+ ? info.newIcon(getContext())
+ : widgetCategoryIcon;
+ mSettingIconDrawable = getResources().getDrawable(R.drawable.ic_setting).mutate();
+ updateSettingColor(info.bitmap.color);
- mDragFlags |= FLAG_DRAW_SETTINGS | FLAG_DRAW_LABEL;
- } else {
- mCenterDrawable = newPendingIcon(getContext(), info);
- mSettingIconDrawable = null;
- applyState();
+ mDragFlags |= FLAG_DRAW_SETTINGS | FLAG_DRAW_LABEL;
+ } else {
+ mCenterDrawable = widgetCategoryIcon == null
+ ? newPendingIcon(getContext(), info)
+ : widgetCategoryIcon;
+ mSettingIconDrawable = null;
+ applyState();
+ }
+ mCenterDrawable.setCallback(this);
+ mDrawableSizeChanged = true;
}
- mCenterDrawable.setCallback(this);
- mDrawableSizeChanged = true;
invalidate();
}
@@ -339,11 +350,6 @@
}
public void applyState() {
- if (mCenterDrawable instanceof FastBitmapDrawable fb
- && mInfo.pendingItemInfo != null
- && !fb.isSameInfo(mInfo.pendingItemInfo.bitmap)) {
- reapplyItemInfo(mInfo.pendingItemInfo);
- }
if (mCenterDrawable != null) {
mCenterDrawable.setLevel(Math.max(mInfo.installProgress, 0));
}
@@ -480,72 +486,16 @@
}
/**
- * Creates a runnable runnable which tries to refresh the widget if it is restored
- */
- public void postProviderAvailabilityCheck() {
- if (!mInfo.hasRestoreFlag(FLAG_PROVIDER_NOT_READY) && getAppWidgetInfo() == null) {
- // If the info state suggests that the provider is ready, but there is no
- // provider info attached on this pending view, recreate when the provider is available
- DeferredWidgetRefresh restoreRunnable = new DeferredWidgetRefresh();
- mOnDetachCleanup.add(restoreRunnable::cleanup);
- mHandler.post(restoreRunnable::notifyWidgetProvidersChanged);
- }
- }
-
- /**
- * Used as a workaround to ensure that the AppWidgetService receives the
- * PACKAGE_ADDED broadcast before updating widgets.
+ * Returns the widget category icon for {@link #mInfo}.
*
- * This class will periodically check for the availability of the WidgetProvider as a result
- * of providerChanged callback from the host. When the provider is available or a timeout of
- * 10-sec is reached, it reinflates the pending-widget which in-turn goes through the process
- * of re-evaluating the pending state of the widget,
+ * <p>If {@link #mInfo}'s category is {@code PackageItemInfo#NO_CATEGORY} or unknown, returns
+ * {@code null}.
*/
- private class DeferredWidgetRefresh implements Runnable, ProviderChangedListener {
- private boolean mRefreshPending = true;
-
- DeferredWidgetRefresh() {
- mWidgetHolder.addProviderChangeListener(this);
- // Force refresh after 10 seconds, if we don't get the provider changed event.
- // This could happen when the provider is no longer available in the app.
- Message msg = Message.obtain(getHandler(), this);
- msg.obj = DeferredWidgetRefresh.class;
- mHandler.sendMessageDelayed(msg, 10000);
+ @Nullable
+ private Drawable getWidgetCategoryIcon() {
+ if (mInfo.pendingItemInfo.widgetCategory == WidgetSections.NO_CATEGORY) {
+ return null;
}
-
- /**
- * Reinflate the widget if it is still attached.
- */
- @Override
- public void run() {
- cleanup();
- if (mRefreshPending) {
- reInflate();
- mRefreshPending = false;
- }
- }
-
- @Override
- public void notifyWidgetProvidersChanged() {
- final AppWidgetProviderInfo widgetInfo;
- WidgetManagerHelper widgetHelper = new WidgetManagerHelper(getContext());
- if (mInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
- widgetInfo = widgetHelper.findProvider(mInfo.providerName, mInfo.user);
- } else {
- widgetInfo = widgetHelper.getLauncherAppWidgetInfo(mInfo.appWidgetId,
- mInfo.getTargetComponent());
- }
- if (widgetInfo != null) {
- run();
- }
- }
-
- /**
- * Removes any scheduled callbacks and change listeners, no-op if nothing is scheduled
- */
- public void cleanup() {
- mWidgetHolder.removeProviderChangeListener(this);
- mHandler.removeCallbacks(this);
- }
+ return mInfo.pendingItemInfo.newIcon(getContext());
}
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java b/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
index faf6b91..f51871b 100644
--- a/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
@@ -27,9 +27,7 @@
import static com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING;
import static com.android.launcher3.Flags.FLAG_USE_NEW_ICON_FOR_ARCHIVED_APPS;
import static com.android.launcher3.LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE;
-import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED;
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.google.common.truth.Truth.assertThat;
@@ -41,8 +39,6 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
import android.graphics.Typeface;
import android.os.Build;
import android.os.UserHandle;
@@ -61,17 +57,13 @@
import com.android.launcher3.Flags;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.Utilities;
-import com.android.launcher3.graphics.PreloadIconDrawable;
-import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
-import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.search.StringMatcherUtility;
import com.android.launcher3.util.ActivityContextWrapper;
import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext;
-import com.android.launcher3.util.TestUtil;
import com.android.launcher3.views.BaseDragLayer;
import org.junit.After;
@@ -81,8 +73,6 @@
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
-import java.util.concurrent.CountDownLatch;
-
/**
* Unit tests for testing modifyTitleToSupportMultiLine() in BubbleTextView.java
* This class tests a couple of strings and uses the getMaxLines() to determine if the test passes.
@@ -495,40 +485,4 @@
assertThat(mBubbleTextView.getIcon().hasBadge()).isEqualTo(true);
}
-
- @Test
- public void applyingPendingIcon_preserves_last_icon() throws Exception {
- mItemInfoWithIcon.bitmap =
- BitmapInfo.fromBitmap(Bitmap.createBitmap(100, 100, Config.ARGB_8888));
- mItemInfoWithIcon.setProgressLevel(30, PackageInstallInfo.STATUS_INSTALLING);
-
- TestUtil.runOnExecutorSync(MAIN_EXECUTOR,
- () -> mBubbleTextView.applyIconAndLabel(mItemInfoWithIcon));
- assertThat(mBubbleTextView.getIcon()).isInstanceOf(PreloadIconDrawable.class);
- assertThat(mBubbleTextView.getIcon().getLevel()).isEqualTo(30);
- PreloadIconDrawable oldIcon = (PreloadIconDrawable) mBubbleTextView.getIcon();
-
- // Same icon is used when progress changes
- mItemInfoWithIcon.setProgressLevel(50, PackageInstallInfo.STATUS_INSTALLING);
- TestUtil.runOnExecutorSync(MAIN_EXECUTOR,
- () -> mBubbleTextView.applyIconAndLabel(mItemInfoWithIcon));
- assertThat(mBubbleTextView.getIcon()).isSameInstanceAs(oldIcon);
- assertThat(mBubbleTextView.getIcon().getLevel()).isEqualTo(50);
-
- // Icon is replaced with a non pending icon when download finishes
- mItemInfoWithIcon.setProgressLevel(100, PackageInstallInfo.STATUS_INSTALLED);
-
- CountDownLatch animWait = new CountDownLatch(1);
- TestUtil.runOnExecutorSync(MAIN_EXECUTOR, () -> {
- mBubbleTextView.applyIconAndLabel(mItemInfoWithIcon);
- assertThat(mBubbleTextView.getIcon()).isSameInstanceAs(oldIcon);
- assertThat(oldIcon.getActiveAnimation()).isNotNull();
- oldIcon.getActiveAnimation().addListener(forEndCallback(animWait::countDown));
- });
- animWait.await();
-
- // Assert that the icon is replaced with a non-pending icon
- assertThat(mBubbleTextView.getIcon()).isNotInstanceOf(PreloadIconDrawable.class);
- }
-
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/LauncherBindableItemsContainerTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/LauncherBindableItemsContainerTest.kt
deleted file mode 100644
index 93be5f5..0000000
--- a/tests/multivalentTests/src/com/android/launcher3/util/LauncherBindableItemsContainerTest.kt
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2025 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.util
-
-import android.content.ComponentName
-import android.content.pm.LauncherApps
-import android.graphics.Bitmap
-import android.graphics.Bitmap.Config.ARGB_8888
-import android.os.Process.myUserHandle
-import android.platform.uiautomatorhelpers.DeviceHelpers.context
-import android.view.View
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.launcher3.BubbleTextView
-import com.android.launcher3.graphics.PreloadIconDrawable
-import com.android.launcher3.icons.BitmapInfo
-import com.android.launcher3.icons.FastBitmapDrawable
-import com.android.launcher3.icons.PlaceHolderIconDrawable
-import com.android.launcher3.model.data.AppInfo
-import com.android.launcher3.model.data.AppInfo.makeLaunchIntent
-import com.android.launcher3.model.data.ItemInfo
-import com.android.launcher3.model.data.WorkspaceItemInfo
-import com.android.launcher3.pm.PackageInstallInfo
-import com.android.launcher3.util.Executors.MAIN_EXECUTOR
-import com.android.launcher3.util.LauncherBindableItemsContainer.ItemOperator
-import com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY
-import com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY2
-import com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY3
-import com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class LauncherBindableItemsContainerTest {
-
- private val icon1 by lazy { getLAI(TEST_ACTIVITY) }
- private val icon2 by lazy { getLAI(TEST_ACTIVITY2) }
- private val icon3 by lazy { getLAI(TEST_ACTIVITY3) }
-
- private val container = TestContainer()
-
- @Test
- fun `icon bitmap is updated`() {
- container.addIcon(icon1)
- container.addIcon(icon2)
- container.addIcon(icon3)
-
- assertThat(container.getAppIcon(icon1).icon)
- .isInstanceOf(PlaceHolderIconDrawable::class.java)
- assertThat(container.getAppIcon(icon2).icon)
- .isInstanceOf(PlaceHolderIconDrawable::class.java)
- assertThat(container.getAppIcon(icon3).icon)
- .isInstanceOf(PlaceHolderIconDrawable::class.java)
-
- icon2.bitmap = BitmapInfo.fromBitmap(Bitmap.createBitmap(200, 200, ARGB_8888))
- TestUtil.runOnExecutorSync(MAIN_EXECUTOR) {
- container.updateContainerItems(setOf(icon2), container)
- }
-
- assertThat(container.getAppIcon(icon1).icon)
- .isInstanceOf(PlaceHolderIconDrawable::class.java)
- assertThat(container.getAppIcon(icon3).icon)
- .isInstanceOf(PlaceHolderIconDrawable::class.java)
- assertThat(container.getAppIcon(icon2).icon)
- .isNotInstanceOf(PlaceHolderIconDrawable::class.java)
- assertThat(container.getAppIcon(icon2).icon).isInstanceOf(FastBitmapDrawable::class.java)
- }
-
- @Test
- fun `icon download progress updated`() {
- container.addIcon(icon1)
- container.addIcon(icon2)
- assertThat(container.getAppIcon(icon1).icon)
- .isInstanceOf(PlaceHolderIconDrawable::class.java)
- assertThat(container.getAppIcon(icon2).icon)
- .isInstanceOf(PlaceHolderIconDrawable::class.java)
-
- icon1.status = WorkspaceItemInfo.FLAG_RESTORED_ICON
- icon1.bitmap = BitmapInfo.fromBitmap(Bitmap.createBitmap(200, 200, ARGB_8888))
- icon1.setProgressLevel(30, PackageInstallInfo.STATUS_INSTALLING)
- TestUtil.runOnExecutorSync(MAIN_EXECUTOR) {
- container.updateContainerItems(setOf(icon1), container)
- }
-
- assertThat(container.getAppIcon(icon2).icon)
- .isInstanceOf(PlaceHolderIconDrawable::class.java)
- assertThat(container.getAppIcon(icon1).icon).isInstanceOf(PreloadIconDrawable::class.java)
- val oldIcon = container.getAppIcon(icon1).icon as PreloadIconDrawable
- assertThat(oldIcon.level).isEqualTo(30)
- }
-
- private fun getLAI(className: String): WorkspaceItemInfo =
- AppInfo(
- context,
- context
- .getSystemService(LauncherApps::class.java)!!
- .resolveActivity(
- makeLaunchIntent(ComponentName(TEST_PACKAGE, className)),
- myUserHandle(),
- )!!,
- myUserHandle(),
- )
- .makeWorkspaceItem(context)
-
- class TestContainer : ActivityContextWrapper(context), LauncherBindableItemsContainer {
-
- val items = mutableMapOf<ItemInfo, View>()
-
- override fun mapOverItems(op: ItemOperator) {
- items.forEach { (item, view) -> if (op.evaluate(item, view)) return@forEach }
- }
-
- fun addIcon(info: WorkspaceItemInfo) {
- val btv = BubbleTextView(this)
- btv.applyFromWorkspaceItem(info)
- items[info] = btv
- }
-
- fun getAppIcon(info: WorkspaceItemInfo) = items[info] as BubbleTextView
- }
-}