Merge "Introduce shortcut container for hotseat event reporting" into ub-launcher3-master
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 54c2383..44d43c6 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -26,10 +26,12 @@
 
 import android.animation.AnimatorSet;
 import android.animation.ValueAnimator;
+import android.app.ActivityOptions;
 import android.content.Intent;
 import android.content.IntentSender;
 import android.os.Bundle;
 import android.os.CancellationSignal;
+import android.view.View;
 
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.WellbeingModel;
@@ -51,6 +53,7 @@
 import com.android.quickstep.views.OverviewActionsView;
 import com.android.quickstep.views.RecentsView;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.ActivityOptionsCompat;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
 
 import java.util.stream.Stream;
@@ -306,6 +309,15 @@
                 Stream.of(WellbeingModel.SHORTCUT_FACTORY));
     }
 
+    @Override
+    public ActivityOptions getActivityLaunchOptions(View v) {
+        ActivityOptions activityOptions = super.getActivityLaunchOptions(v);
+        if (activityOptions != null && mLastTouchUpTime > 0) {
+            ActivityOptionsCompat.setLauncherSourceInfo(activityOptions, mLastTouchUpTime);
+        }
+        return activityOptions;
+    }
+
     public void setHintUserWillBeActive() {
         addActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE);
     }
diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
index dbdfd8d..f313d75 100644
--- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -148,10 +148,6 @@
 
     private void updateVisibility() {
         setVisibility(mPredictionsEnabled ? VISIBLE : GONE);
-        if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && mLauncher.getAppsView() != null
-                && mLauncher.getAppsView().getActiveRecyclerView() != null) {
-            mLauncher.getAppsView().invalidate();
-        }
     }
 
     @Override
@@ -170,6 +166,7 @@
             }
             mDecorationHandler.onDraw(canvas);
             mDecorationHandler.onFocusDraw(canvas, getFocusedChild());
+            mLauncher.getAppsView().getActiveRecyclerView().invalidateItemDecorations();
         }
         mFocusHelper.draw(canvas);
         super.dispatchDraw(canvas);
@@ -184,7 +181,7 @@
 
     @Override
     public boolean shouldDraw() {
-        return getVisibility() != GONE;
+        return getVisibility() == VISIBLE;
     }
 
     @Override
@@ -209,7 +206,7 @@
      * we can optimize by swapping them in place.
      */
     public void setPredictedApps(List<ItemInfo> items) {
-        if (isShown() && getWindowVisibility() == View.VISIBLE) {
+        if (!mLauncher.isWorkspaceLoading() && isShown() && getWindowVisibility() == View.VISIBLE) {
             mPendingPredictedItems = items;
             return;
         }
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
index 76bab59..d3b7e22 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
@@ -251,7 +251,9 @@
      * Sets or updates the predicted items
      */
     public void setPredictedItems(FixedContainerItems items) {
-        if (mHotseat.isShown() && mHotseat.getWindowVisibility() == View.VISIBLE) {
+        if (!mLauncher.isWorkspaceLoading()
+                && mHotseat.isShown()
+                && mHotseat.getWindowVisibility() == View.VISIBLE) {
             mHotseat.setOnVisibilityAggregatedCallback((isVisible) -> {
                 if (isVisible) {
                     return;
diff --git a/quickstep/src/com/android/launcher3/model/WellbeingModel.java b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
index a9fc1aa..995c4b0 100644
--- a/quickstep/src/com/android/launcher3/model/WellbeingModel.java
+++ b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
@@ -148,6 +148,12 @@
             if (!FeatureFlags.ENABLE_MINIMAL_DEVICE.get()) {
                 return;
             }
+
+            // Temporary bug fix for b/169771796. Wellbeing provides the layout configuration when
+            // minimal device is enabled. We always want to reload the configuration from Wellbeing
+            // since the layout configuration might have changed.
+            mContext.deleteDatabase(DB_NAME_MINIMAL_DEVICE);
+
             final Bundle extras = new Bundle();
             String dbFile;
             if (isInMinimalDeviceMode()) {
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index b43d63b..cc109f6 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -1339,7 +1339,7 @@
                 if (taskView != null && !mCanceled) {
                     // Defer finishing the animation until the next launcher frame with the
                     // new thumbnail
-                    finishTransitionPosted = ViewUtils.postDraw(taskView,
+                    finishTransitionPosted = ViewUtils.postFrameDrawn(taskView,
                             () -> mStateCallback.setStateOnUiThread(STATE_SCREENSHOT_CAPTURED),
                             this::isCanceled);
                 }
@@ -1479,6 +1479,11 @@
         mGestureEndCallback = gestureEndCallback;
     }
 
+    @Override
+    public long getStartTouchTime() {
+        return mTouchTimeMs;
+    }
+
     protected void linkRecentsViewScroll() {
         SurfaceTransactionApplier.create(mRecentsView, applier -> {
             mTransformParams.setSyncTransactionApplier(applier);
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index a21c714..f319b94 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -160,5 +160,12 @@
          * Callback made when a task started from the recents is ready for an app transition.
          */
         default void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {}
+
+        /**
+         * The time in milliseconds of the touch event that starts the recents animation.
+         */
+        default long getStartTouchTime() {
+            return 0;
+        }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index a46de1f..7406dea 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -261,7 +261,7 @@
             mTransformParams
                     .setTargetAlpha(getWindowAlpha(progress))
                     .setCornerRadius(cornerRadius)
-                    .setShadowRadius(mMaxShadowRadius);
+                    .setShadowRadius(shadowRadius);
 
             mTransformParams.applySurfaceParams(mTransformParams.createSurfaceParams(this));
             mAnimationFactory.update(currentRect, progress, mMatrix.mapRadius(cornerRadius));
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 2666869..a214d81 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -17,7 +17,10 @@
 
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 
+import android.app.PictureInPictureParams;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.ActivityInfo;
 import android.graphics.Bitmap;
 import android.graphics.Insets;
 import android.graphics.Rect;
@@ -380,4 +383,29 @@
             }
         }
     }
+
+    @Override
+    public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
+            PictureInPictureParams pictureInPictureParams, int launcherRotation, int shelfHeight) {
+        if (mSystemUiProxy != null) {
+            try {
+                return mSystemUiProxy.startSwipePipToHome(componentName, activityInfo,
+                        pictureInPictureParams, launcherRotation, shelfHeight);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call startSwipePipToHome", e);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
+        if (mSystemUiProxy != null) {
+            try {
+                mSystemUiProxy.stopSwipePipToHome(componentName, destinationBounds);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call stopSwipePipToHome");
+            }
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index f38c1ea..797797f 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -50,7 +50,7 @@
     public void preloadRecentsAnimation(Intent intent) {
         // Pass null animation handler to indicate this start is for preloading
         UI_HELPER_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance()
-                .startRecentsActivity(intent, null, null, null, null));
+                .startRecentsActivity(intent, 0, null, null, null));
     }
 
     /**
@@ -119,10 +119,11 @@
                 }
             }
         });
+        final long eventTime = listener.getStartTouchTime();
         mCallbacks.addListener(gestureState);
         mCallbacks.addListener(listener);
         UI_HELPER_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance()
-                .startRecentsActivity(intent, null, mCallbacks, null, null));
+                .startRecentsActivity(intent, eventTime, mCallbacks, null, null));
         gestureState.setState(STATE_RECENTS_ANIMATION_INITIALIZED);
         return mCallbacks;
     }
diff --git a/quickstep/src/com/android/quickstep/ViewUtils.java b/quickstep/src/com/android/quickstep/ViewUtils.java
index cbb6ad4..184ab17 100644
--- a/quickstep/src/com/android/quickstep/ViewUtils.java
+++ b/quickstep/src/com/android/quickstep/ViewUtils.java
@@ -15,21 +15,23 @@
  */
 package com.android.quickstep;
 
-import android.graphics.Canvas;
+import android.os.Handler;
 import android.view.View;
 
-import com.android.systemui.shared.system.WindowCallbacksCompat;
+import com.android.launcher3.Utilities;
+import com.android.systemui.shared.system.ViewRootImplCompat;
 
 import java.util.function.BooleanSupplier;
+import java.util.function.LongConsumer;
 
 /**
  * Utility class for helpful methods related to {@link View} objects.
  */
 public class ViewUtils {
 
-    /** See {@link #postDraw(View, Runnable, BooleanSupplier)}} */
-    public static boolean postDraw(View view, Runnable onFinishRunnable) {
-        return postDraw(view, onFinishRunnable, () -> false);
+    /** See {@link #postFrameDrawn(View, Runnable, BooleanSupplier)}} */
+    public static boolean postFrameDrawn(View view, Runnable onFinishRunnable) {
+        return postFrameDrawn(view, onFinishRunnable, () -> false);
     }
 
     /**
@@ -38,37 +40,55 @@
      *
      * @param onFinishRunnable runnable to be run right after the view finishes drawing.
      */
-    public static boolean postDraw(View view, Runnable onFinishRunnable, BooleanSupplier canceled) {
-        // Defer finishing the animation until the next launcher frame with the
-        // new thumbnail
-        return new WindowCallbacksCompat(view) {
-            // The number of frames to defer until we actually finish the animation
-            private int mDeferFrameCount = 2;
+    public static boolean postFrameDrawn(
+            View view, Runnable onFinishRunnable, BooleanSupplier canceled) {
+        return new FrameHandler(view, onFinishRunnable, canceled).schedule();
+    }
 
-            @Override
-            public void onPostDraw(Canvas canvas) {
-                // If we were cancelled after this was attached, do not update
-                // the state.
-                if (canceled.getAsBoolean()) {
-                    detach();
-                    return;
-                }
+    private static class FrameHandler implements LongConsumer {
 
-                if (mDeferFrameCount > 0) {
-                    mDeferFrameCount--;
-                    // Workaround, detach and reattach to invalidate the root node for
-                    // another draw
-                    detach();
-                    attach();
-                    view.invalidate();
-                    return;
-                }
+        final ViewRootImplCompat mViewRoot;
+        final Runnable mFinishCallback;
+        final BooleanSupplier mCancelled;
+        final Handler mHandler;
 
-                if (onFinishRunnable != null) {
-                    onFinishRunnable.run();
-                }
-                detach();
+        int mDeferFrameCount = 1;
+
+        FrameHandler(View view, Runnable finishCallback, BooleanSupplier cancelled) {
+            mViewRoot = new ViewRootImplCompat(view);
+            mFinishCallback = finishCallback;
+            mCancelled = cancelled;
+            mHandler = new Handler();
+        }
+
+        @Override
+        public void accept(long l) {
+            Utilities.postAsyncCallback(mHandler, this::onFrame);
+        }
+
+        private void onFrame() {
+            if (mCancelled.getAsBoolean()) {
+                return;
             }
-        }.attach();
+
+            if (mDeferFrameCount > 0) {
+                mDeferFrameCount--;
+                schedule();
+                return;
+            }
+
+            if (mFinishCallback != null) {
+                mFinishCallback.run();
+            }
+        }
+
+        private boolean schedule() {
+            if (mViewRoot.isValid()) {
+                mViewRoot.registerRtFrameCallback(this);
+                mViewRoot.getView().invalidate();
+                return true;
+            }
+            return false;
+        }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 65a445b..2158e03 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -2452,7 +2452,7 @@
             } else {
                 taskView.getThumbnail().refresh();
             }
-            ViewUtils.postDraw(taskView, onFinishRunnable);
+            ViewUtils.postFrameDrawn(taskView, onFinishRunnable);
         } else {
             onFinishRunnable.run();
         }
diff --git a/res/layout/all_apps_tabs.xml b/res/layout/all_apps_tabs.xml
index 2accd2d..c684881 100644
--- a/res/layout/all_apps_tabs.xml
+++ b/res/layout/all_apps_tabs.xml
@@ -26,7 +26,6 @@
     android:clipChildren="true"
     android:clipToPadding="false"
     android:descendantFocusability="afterDescendants"
-    android:paddingTop="@dimen/all_apps_header_top_padding"
     launcher:pageIndicator="@+id/tabs" >
 
     <include layout="@layout/all_apps_rv_layout" />
diff --git a/res/layout/search_section_title.xml b/res/layout/search_section_title.xml
index c541631..b7ba83e 100644
--- a/res/layout/search_section_title.xml
+++ b/res/layout/search_section_title.xml
@@ -17,8 +17,9 @@
     android:id="@+id/section_title"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:fontFamily="@style/TextHeadline"
-    android:textStyle="bold"
-    android:padding="4dp"
+    style="@style/TextHeadline"
+    android:paddingStart="4dp"
+    android:paddingBottom="2dp"
+    android:paddingTop="12dp"
     android:textColor="?android:attr/textColorPrimary"
-    android:textSize="14sp" />
\ No newline at end of file
+    android:textSize="18sp" />
\ No newline at end of file
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 4b75a33..ab8d7a5 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -77,6 +77,7 @@
 import android.os.Parcelable;
 import android.os.Process;
 import android.os.StrictMode;
+import android.os.SystemClock;
 import android.text.TextUtils;
 import android.text.method.TextKeyListener;
 import android.util.Log;
@@ -350,7 +351,7 @@
     private boolean mDeferOverlayCallbacks;
     private final Runnable mDeferredOverlayCallbacks = this::checkIfOverlayStillDeferred;
 
-    private long mLastTouchUpTime = -1;
+    protected long mLastTouchUpTime = -1;
     private boolean mTouchInProgress;
 
     private SafeCloseable mUserChangedCallbackCloseable;
@@ -1828,7 +1829,7 @@
                 mTouchInProgress = true;
                 break;
             case MotionEvent.ACTION_UP:
-                mLastTouchUpTime = System.currentTimeMillis();
+                mLastTouchUpTime = ev.getEventTime();
                 // Follow through
             case MotionEvent.ACTION_CANCEL:
                 mTouchInProgress = false;
@@ -2461,7 +2462,7 @@
         if (mDragController.isDragging()) {
             return false;
         } else {
-            return (System.currentTimeMillis() - mLastTouchUpTime)
+            return (SystemClock.uptimeMillis() - mLastTouchUpTime)
                     > (NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS * 1000);
         }
     }
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 5079469..75ab00a 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -585,10 +585,6 @@
         int padding = mHeader.getMaxTranslation();
         for (int i = 0; i < mAH.length; i++) {
             mAH[i].padding.top = padding;
-            if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && mUsingTabs) {
-                //add extra space between tabs and recycler view
-                mAH[i].padding.top += mLauncher.getDeviceProfile().edgeMarginPx;
-            }
             mAH[i].applyPadding();
         }
     }
diff --git a/src/com/android/launcher3/allapps/AllAppsPagedView.java b/src/com/android/launcher3/allapps/AllAppsPagedView.java
index f640c3e..eae9c0a 100644
--- a/src/com/android/launcher3/allapps/AllAppsPagedView.java
+++ b/src/com/android/launcher3/allapps/AllAppsPagedView.java
@@ -20,6 +20,8 @@
 import android.view.MotionEvent;
 
 import com.android.launcher3.PagedView;
+import com.android.launcher3.R;
+import com.android.launcher3.config.FeatureFlags;
 
 public class AllAppsPagedView extends PagedView<PersonalWorkSlidingTabStrip> {
 
@@ -37,6 +39,9 @@
 
     public AllAppsPagedView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
+        int topPadding = FeatureFlags.ENABLE_DEVICE_SEARCH.get() ? 0
+                : context.getResources().getDimensionPixelOffset(
+                        R.dimen.all_apps_header_top_padding);
     }
 
     @Override
diff --git a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
index f2a1f85..c131697 100644
--- a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
+++ b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
@@ -26,6 +26,7 @@
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.launcher3.R;
+import com.android.launcher3.allapps.AllAppsGridAdapter.AppsGridLayoutManager;
 import com.android.launcher3.allapps.search.SearchSectionInfo;
 import com.android.launcher3.util.Themes;
 
@@ -90,7 +91,10 @@
         if (mAppsView.getFloatingHeaderView().getFocusedChild() == null
                 && mAppsView.getApps().getFocusedChild() != null) {
             int index = mAppsView.getApps().getFocusedChildIndex();
-            if (index >= 0 && index < parent.getChildCount()) {
+            AppsGridLayoutManager layoutManager = (AppsGridLayoutManager)
+                    mAppsView.getActiveRecyclerView().getLayoutManager();
+            if (layoutManager.findFirstVisibleItemPosition() == index
+                    && index < parent.getChildCount()) {
                 decorationHandler.onFocusDraw(c, parent.getChildAt(index));
             }
         }
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index 4bb6a00..813db7d 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -200,7 +200,7 @@
     public View getFocusedChild() {
         if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
             for (FloatingHeaderRow row : mAllRows) {
-                if (row.hasVisibleContent()) {
+                if (row.hasVisibleContent() && row.shouldDraw()) {
                     return row.getFocusedChild();
                 }
             }
diff --git a/src/com/android/launcher3/views/SearchResultPlayItem.java b/src/com/android/launcher3/views/SearchResultPlayItem.java
index d05a29e..c7133fd 100644
--- a/src/com/android/launcher3/views/SearchResultPlayItem.java
+++ b/src/com/android/launcher3/views/SearchResultPlayItem.java
@@ -44,12 +44,14 @@
 import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
 import com.android.launcher3.allapps.search.AllAppsSearchBarController;
 import com.android.launcher3.icons.BitmapRenderer;
+import com.android.launcher3.util.Themes;
 import com.android.systemui.plugins.AllAppsSearchPlugin;
 import com.android.systemui.plugins.shared.SearchTarget;
 import com.android.systemui.plugins.shared.SearchTargetEvent;
 
 import java.io.IOException;
 import java.net.URL;
+import java.net.URLConnection;
 
 /**
  * A View representing a PlayStore item.
@@ -58,7 +60,6 @@
         AllAppsSearchBarController.PayloadResultHandler<Bundle> {
 
     private static final int BITMAP_CROP_MASK_COLOR = 0xff424242;
-    private static final float ICON_RADIUS_FACTOR = .5f;
 
     private final DeviceProfile mDeviceProfile;
     private View mIconView;
@@ -71,6 +72,7 @@
     private final Object[] mTargetInfo = createTargetInfo();
 
     final Paint mIconPaint = new Paint();
+    final Rect mTempRect = new Rect();
 
 
     public SearchResultPlayItem(Context context) {
@@ -125,13 +127,15 @@
         mIconView.setBackgroundResource(R.drawable.ic_deepshortcut_placeholder);
         UI_HELPER_EXECUTOR.execute(() -> {
             try {
-//                TODO: Handle caching
                 URL url = new URL(bundle.getString("icon_url"));
-                Bitmap bitmap = BitmapFactory.decodeStream(url.openStream());
-                BitmapDrawable bitmapDrawable = new BitmapDrawable(getResources(),
-                        Bitmap.createScaledBitmap(getRoundedBitmap(bitmap),
-                                mDeviceProfile.allAppsIconSizePx, mDeviceProfile.allAppsIconSizePx,
-                                false));
+                URLConnection con = url.openConnection();
+//                TODO: monitor memory and investigate if it's better to use glide
+                con.addRequestProperty("Cache-Control", "max-age: 0");
+                con.setUseCaches(true);
+                Bitmap bitmap = BitmapFactory.decodeStream(con.getInputStream());
+                BitmapDrawable bitmapDrawable = new BitmapDrawable(getResources(), getRoundedBitmap(
+                        Bitmap.createScaledBitmap(bitmap, mDeviceProfile.allAppsIconSizePx,
+                                mDeviceProfile.allAppsIconSizePx, false)));
                 mIconView.post(() -> mIconView.setBackground(bitmapDrawable));
             } catch (IOException e) {
                 e.printStackTrace();
@@ -141,24 +145,23 @@
 
 
     private Bitmap getRoundedBitmap(Bitmap bitmap) {
-        int iconSize = bitmap.getWidth();
+        final int iconSize = bitmap.getWidth();
+        final float radius = Themes.getDialogCornerRadius(getContext());
 
         Bitmap output = BitmapRenderer.createHardwareBitmap(iconSize, iconSize, (canvas) -> {
-            final Rect rect = new Rect(0, 0, iconSize, iconSize);
-            final RectF rectF = new RectF(rect);
+            mTempRect.set(0, 0, iconSize, iconSize);
+            final RectF rectF = new RectF(mTempRect);
 
             mIconPaint.setAntiAlias(true);
+            mIconPaint.reset();
             canvas.drawARGB(0, 0, 0, 0);
             mIconPaint.setColor(BITMAP_CROP_MASK_COLOR);
-            int radius = (int) (iconSize * ICON_RADIUS_FACTOR);
             canvas.drawRoundRect(rectF, radius, radius, mIconPaint);
 
             mIconPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
-            canvas.drawBitmap(bitmap, rect, rect, mIconPaint);
+            canvas.drawBitmap(bitmap, mTempRect, mTempRect, mIconPaint);
         });
-
         return output;
-
     }