Update FloatingIconView to display PreloadIconDrawables during swipe home animations.

Swiping up to go home on an app that is downloading incrementally would cause a jittery animation. Updated FloatingIconView to animate directly to a PreloadIconDrawable.

Demo: https://drive.google.com/file/d/1ddr8OGR4c1ZneyQ0VkkAAxGpwNcP8Wyn/view?usp=sharing

Fixes: 177685929

Test: manual
Change-Id: I4cd2daa18f6d3fed42a9b666063e0b1c1c46e5d9
(cherry picked from commit b8cab8d878)
This commit is contained in:
Schneider Victor-tulias
2021-01-21 14:41:07 -08:00
parent 14faee73e7
commit b40b98db3a
6 changed files with 124 additions and 43 deletions

View File

@@ -301,7 +301,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
verifyHighRes();
if ((info.runtimeStatusFlags & ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) {
applyProgressLevel(info.getProgressLevel());
applyProgressLevel();
}
applyDotState(info, false /* animate */);
}
@@ -603,21 +603,20 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
* with the total download progress.
*/
public void applyLoadingState(boolean promiseStateChanged) {
if (getTag() instanceof WorkspaceItemInfo) {
if (getTag() instanceof ItemInfoWithIcon) {
WorkspaceItemInfo info = (WorkspaceItemInfo) getTag();
int progressLevel = info.getProgressLevel();
if ((info.runtimeStatusFlags & ItemInfoWithIcon.FLAG_INCREMENTAL_DOWNLOAD_ACTIVE)
!= 0) {
updateProgressBarUi(progressLevel, progressLevel == 100);
updateProgressBarUi(info.getProgressLevel() == 100);
} else if (info.hasPromiseIconUi() || (info.runtimeStatusFlags
& ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) {
updateProgressBarUi(progressLevel, promiseStateChanged);
& ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) {
updateProgressBarUi(promiseStateChanged);
}
}
}
private void updateProgressBarUi(int progressLevel, boolean maybePerformFinishedAnimation) {
PreloadIconDrawable preloadDrawable = applyProgressLevel(progressLevel);
private void updateProgressBarUi(boolean maybePerformFinishedAnimation) {
PreloadIconDrawable preloadDrawable = applyProgressLevel();
if (preloadDrawable != null && maybePerformFinishedAnimation) {
preloadDrawable.maybePerformFinishedAnimation();
}
@@ -625,38 +624,59 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
/** Applies the given progress level to the this icon's progress bar. */
@Nullable
public PreloadIconDrawable applyProgressLevel(int progressLevel) {
if (getTag() instanceof ItemInfoWithIcon) {
ItemInfoWithIcon info = (ItemInfoWithIcon) getTag();
if (progressLevel >= 100) {
setContentDescription(info.contentDescription != null
? info.contentDescription : "");
} else if (progressLevel > 0) {
setContentDescription(getContext()
.getString(R.string.app_downloading_title, info.title,
NumberFormat.getPercentInstance().format(progressLevel * 0.01)));
public PreloadIconDrawable applyProgressLevel() {
if (!(getTag() instanceof ItemInfoWithIcon)) {
return null;
}
ItemInfoWithIcon info = (ItemInfoWithIcon) getTag();
int progressLevel = info.getProgressLevel();
if (progressLevel >= 100) {
setContentDescription(info.contentDescription != null
? info.contentDescription : "");
} else if (progressLevel > 0) {
setContentDescription(getContext()
.getString(R.string.app_downloading_title, info.title,
NumberFormat.getPercentInstance().format(progressLevel * 0.01)));
} else {
setContentDescription(getContext()
.getString(R.string.app_waiting_download_title, info.title));
}
if (mIcon != null) {
PreloadIconDrawable preloadIconDrawable;
if (mIcon instanceof PreloadIconDrawable) {
preloadIconDrawable = (PreloadIconDrawable) mIcon;
preloadIconDrawable.setLevel(progressLevel);
preloadIconDrawable.setIsDisabled(!info.isAppStartable());
} else {
setContentDescription(getContext()
.getString(R.string.app_waiting_download_title, info.title));
}
if (mIcon != null) {
final PreloadIconDrawable preloadDrawable;
if (mIcon instanceof PreloadIconDrawable) {
preloadDrawable = (PreloadIconDrawable) mIcon;
preloadDrawable.setLevel(progressLevel);
preloadDrawable.setIsDisabled(!info.isAppStartable());
} else {
preloadDrawable = newPendingIcon(getContext(), info);
preloadDrawable.setLevel(progressLevel);
preloadDrawable.setIsDisabled(!info.isAppStartable());
setIcon(preloadDrawable);
}
return preloadDrawable;
preloadIconDrawable = makePreloadIcon();
setIcon(preloadIconDrawable);
}
return preloadIconDrawable;
}
return null;
}
/**
* Creates a PreloadIconDrawable with the appropriate progress level without mutating this
* object.
*/
@Nullable
public PreloadIconDrawable makePreloadIcon() {
if (!(getTag() instanceof ItemInfoWithIcon)) {
return null;
}
ItemInfoWithIcon info = (ItemInfoWithIcon) getTag();
int progressLevel = info.getProgressLevel();
final PreloadIconDrawable preloadDrawable = newPendingIcon(getContext(), info);
preloadDrawable.setLevel(progressLevel);
preloadDrawable.setIsDisabled(!info.isAppStartable());
return preloadDrawable;
}
public void applyDotState(ItemInfo itemInfo, boolean animate) {
if (mIcon instanceof FastBitmapDrawable) {
boolean wasDotted = mDotInfo != null;

View File

@@ -276,15 +276,15 @@ public class FastBitmapDrawable extends Drawable {
@Override
public ConstantState getConstantState() {
return new MyConstantState(mBitmap, mIconColor, mIsDisabled);
return new FastBitmapConstantState(mBitmap, mIconColor, mIsDisabled);
}
protected static class MyConstantState extends ConstantState {
protected static class FastBitmapConstantState extends ConstantState {
protected final Bitmap mBitmap;
protected final int mIconColor;
protected final boolean mIsDisabled;
public MyConstantState(Bitmap bitmap, int color, boolean isDisabled) {
public FastBitmapConstantState(Bitmap bitmap, int color, boolean isDisabled) {
mBitmap = bitmap;
mIconColor = color;
mIsDisabled = isDisabled;

View File

@@ -154,7 +154,7 @@ public class AllAppsStore {
public void updateProgressBar(AppInfo app) {
updateAllIcons((child) -> {
if (child.getTag() == app) {
child.applyProgressLevel(app.getProgressLevel());
child.applyProgressLevel();
}
});
}

View File

@@ -105,6 +105,10 @@ public class PreloadIconDrawable extends FastBitmapDrawable {
private ObjectAnimator mCurrentAnim;
public PreloadIconDrawable(ItemInfoWithIcon info, Context context) {
this(info, IconPalette.getPreloadProgressColor(context, info.bitmap.color));
}
public PreloadIconDrawable(ItemInfoWithIcon info, int indicatorColor) {
super(info.bitmap);
mItem = info;
mShapePath = getShapePath();
@@ -114,7 +118,7 @@ public class PreloadIconDrawable extends FastBitmapDrawable {
mProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
mProgressPaint.setStyle(Paint.Style.STROKE);
mProgressPaint.setStrokeCap(Paint.Cap.ROUND);
mIndicatorColor = IconPalette.getPreloadProgressColor(context, mIconColor);
mIndicatorColor = indicatorColor;
setInternalProgress(0);
@@ -297,4 +301,42 @@ public class PreloadIconDrawable extends FastBitmapDrawable {
public static PreloadIconDrawable newPendingIcon(Context context, ItemInfoWithIcon info) {
return new PreloadIconDrawable(info, context);
}
@Override
public ConstantState getConstantState() {
return new PreloadIconConstantState(
mBitmap, mIconColor, !mItem.isAppStartable(), mItem, mIndicatorColor);
}
protected static class PreloadIconConstantState extends FastBitmapConstantState {
protected final ItemInfoWithIcon mInfo;
protected final int mIndicatorColor;
protected final int mLevel;
public PreloadIconConstantState(
Bitmap bitmap,
int iconColor,
boolean isDisabled,
ItemInfoWithIcon info,
int indicatorcolor) {
super(bitmap, iconColor, isDisabled);
mInfo = info;
mIndicatorColor = indicatorcolor;
mLevel = info.getProgressLevel();
}
@Override
public PreloadIconDrawable newDrawable() {
PreloadIconDrawable drawable = new PreloadIconDrawable(mInfo, mIndicatorColor);
drawable.setLevel(mLevel);
drawable.setIsDisabled(mIsDisabled);
return drawable;
}
@Override
public int getChangingConfigurations() {
return 0;
}
}
}

View File

@@ -308,7 +308,7 @@ public class ClockDrawableWrapper extends AdaptiveIconDrawable implements Bitmap
return new ClockConstantState(mInfo, isDisabled());
}
private static class ClockConstantState extends MyConstantState {
private static class ClockConstantState extends FastBitmapConstantState {
private final ClockBitmapInfo mInfo;

View File

@@ -51,8 +51,10 @@ import com.android.launcher3.Utilities;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.graphics.PreloadIconDrawable;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.shortcuts.DeepShortcutView;
@@ -252,12 +254,26 @@ public class FloatingIconView extends FrameLayout implements
@SuppressWarnings("WrongThread")
private static void getIconResult(Launcher l, View originalView, ItemInfo info, RectF pos,
IconLoadResult iconLoadResult) {
Drawable drawable = null;
Drawable drawable;
Drawable btvIcon;
Drawable badge = null;
boolean supportsAdaptiveIcons = ADAPTIVE_ICON_WINDOW_ANIM.get()
&& !info.isDisabled(); // Use original icon for disabled icons.
Drawable btvIcon = originalView instanceof BubbleTextView
? ((BubbleTextView) originalView).getIcon() : null;
if (originalView instanceof BubbleTextView) {
BubbleTextView btv = (BubbleTextView) originalView;
if (info instanceof ItemInfoWithIcon
&& (((ItemInfoWithIcon) info).runtimeStatusFlags
& ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) {
btvIcon = btv.makePreloadIcon();
} else {
btvIcon = btv.getIcon();
}
} else {
btvIcon = null;
}
if (info instanceof SystemShortcut) {
if (originalView instanceof ImageView) {
drawable = ((ImageView) originalView).getDrawable();
@@ -266,6 +282,9 @@ public class FloatingIconView extends FrameLayout implements
} else {
drawable = originalView.getBackground();
}
} else if (btvIcon instanceof PreloadIconDrawable) {
// Force the progress bar to display.
drawable = btvIcon;
} else {
int width = (int) pos.width();
int height = (int) pos.height();