Merge "Reducing delay in applying widget previews loaded in the background." into ub-launcher3-burnaby
diff --git a/proguard.flags b/proguard.flags
index 6eb5948..5e2c384 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -1,19 +1,3 @@
--keep class com.android.launcher3.Launcher {
-  public void previousScreen(android.view.View);
-  public void nextScreen(android.view.View);
-  public void launchHotSeat(android.view.View);
-  public void onClickSearchButton(android.view.View);
-  public void onClickVoiceButton(android.view.View);
-  public void onClickConfigureButton(android.view.View);
-  public void onClickAllAppsButton(android.view.View);
-  public void dismissFirstRunCling(android.view.View);
-  public void dismissMigrationClingCopyApps(android.view.View);
-  public void dismissMigrationClingUseDefault(android.view.View);
-  public void dismissMigrationWorkspaceCling(android.view.View);
-  public void dismissWorkspaceCling(android.view.View);
-  public void dismissAllAppsCling(android.view.View);
-}
-
 -keep class com.android.launcher3.CellLayout {
   public float getBackgroundAlpha();
   public void setBackgroundAlpha(float);
@@ -44,8 +28,6 @@
 -keep class com.android.launcher3.Workspace {
   public float getBackgroundAlpha();
   public void setBackgroundAlpha(float);
-  public float getChildrenOutlineAlpha();
-  public void setChildrenOutlineAlpha(float);
 }
 
 -keep class com.android.launcher3.MemoryDumpActivity {
diff --git a/res/layout/widgets_list_row_view.xml b/res/layout/widgets_list_row_view.xml
index dc1bcce..67b4acb 100644
--- a/res/layout/widgets_list_row_view.xml
+++ b/res/layout/widgets_list_row_view.xml
@@ -19,6 +19,7 @@
     android:id="@+id/widgets_cell_list_container"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:background="@color/widgets_cell_color"
     android:orientation="vertical"
     android:focusable="true"
     android:descendantFocusability="afterDescendants">
@@ -52,7 +53,7 @@
         android:id="@+id/widgets_scroll_container"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:scrollbars="none" >
+        android:scrollbars="none">
         <LinearLayout
             android:id="@+id/widgets_cell_list"
             android:layout_width="wrap_content"
@@ -61,7 +62,6 @@
             android:layout_marginLeft="@dimen/widget_row_padding"
             android:orientation="horizontal"
             android:divider="@drawable/widgets_row_divider"
-            android:showDividers="middle"
-            android:background="@color/widgets_cell_color"/>
+            android:showDividers="middle"/>
     </HorizontalScrollView>
 </LinearLayout>
diff --git a/res/layout/widgets_view.xml b/res/layout/widgets_view.xml
index 1857595..9d9fa10 100644
--- a/res/layout/widgets_view.xml
+++ b/res/layout/widgets_view.xml
@@ -34,19 +34,12 @@
         android:focusable="false"
         android:visibility="invisible" />
 
-    <LinearLayout
-        android:id="@+id/widgets_content"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:clipChildren="false"
-        android:elevation="15dp"
-        android:visibility="gone"
-        android:orientation="vertical" >
-
         <com.android.launcher3.widget.WidgetsContainerRecyclerView
-                android:id="@+id/widgets_list_view"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:background="@drawable/quantum_panel_dark"/>
-    </LinearLayout>
+            android:id="@+id/widgets_list_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:background="@drawable/quantum_panel_dark"
+            android:elevation="15dp"
+            android:visibility="gone" />
+
 </com.android.launcher3.widget.WidgetsContainerView>
\ No newline at end of file
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index edcdc11..1d211bf 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -103,8 +103,6 @@
     private float FOREGROUND_ALPHA_DAMPER = 0.65f;
     private int mForegroundAlpha = 0;
     private float mBackgroundAlpha;
-    private float mBackgroundAlphaMultiplier = 1.0f;
-    private boolean mDrawBackground = true;
 
     private Drawable mNormalBackground;
     private Drawable mActiveGlowBackground;
@@ -423,10 +421,6 @@
         }
     }
 
-    void disableBackground() {
-        mDrawBackground = false;
-    }
-
     void disableDragTarget() {
         mIsDragTarget = false;
     }
@@ -448,12 +442,16 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
+        if (!mIsDragTarget) {
+            return;
+        }
+
         // When we're large, we are either drawn in a "hover" state (ie when dragging an item to
         // a neighboring page) or with just a normal background (if backgroundAlpha > 0.0f)
         // When we're small, we are either drawn normally or in the "accepts drops" state (during
         // a drag). However, we also drag the mini hover background *over* one of those two
         // backgrounds
-        if (mDrawBackground && mBackgroundAlpha > 0.0f) {
+        if (mBackgroundAlpha > 0.0f) {
             Drawable bg;
 
             if (mIsDragOverlapping) {
@@ -463,7 +461,7 @@
                 bg = mNormalBackground;
             }
 
-            bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255));
+            bg.setAlpha((int) (mBackgroundAlpha * 255));
             bg.setBounds(mBackgroundRect);
             bg.draw(canvas);
         }
@@ -951,17 +949,6 @@
         return mBackgroundAlpha;
     }
 
-    public void setBackgroundAlphaMultiplier(float multiplier) {
-        if (mBackgroundAlphaMultiplier != multiplier) {
-            mBackgroundAlphaMultiplier = multiplier;
-            invalidate();
-        }
-    }
-
-    public float getBackgroundAlphaMultiplier() {
-        return mBackgroundAlphaMultiplier;
-    }
-
     public void setBackgroundAlpha(float alpha) {
         if (mBackgroundAlpha != alpha) {
             mBackgroundAlpha = alpha;
diff --git a/src/com/android/launcher3/FolderPagedView.java b/src/com/android/launcher3/FolderPagedView.java
index de30b60..06ed588 100644
--- a/src/com/android/launcher3/FolderPagedView.java
+++ b/src/com/android/launcher3/FolderPagedView.java
@@ -241,6 +241,11 @@
         return page;
     }
 
+    @Override
+    protected int getChildGap() {
+        return getPaddingLeft() + getPaddingRight();
+    }
+
     public void setFixedSize(int width, int height) {
         width -= (getPaddingLeft() + getPaddingRight());
         height -= (getPaddingTop() + getPaddingBottom());
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index fff07c6..1fac5a1 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -46,12 +46,14 @@
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.widget.PackageItemInfo;
 
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map.Entry;
+import java.util.Stack;
 
 /**
  * Cache of application icons.  Icons can be made from any thread.
@@ -281,7 +283,7 @@
                 itemsToRemove.add(c.getInt(rowIndex));
                 continue;
             }
-            ContentValues values = updateCacheAndGetContentValues(app);
+            ContentValues values = updateCacheAndGetContentValues(app, true);
             mIconDb.getWritableDatabase().update(IconDB.TABLE_NAME, values,
                     IconDB.COLUMN_COMPONENT + " = ? AND " + IconDB.COLUMN_USER + " = ?",
                     new String[] {cn, Long.toString(userSerial)});
@@ -296,21 +298,19 @@
         }
 
         // Insert remaining apps.
-        for (LauncherActivityInfoCompat app : componentMap.values()) {
-            PackageInfo info = pkgInfoMap.get(app.getComponentName().getPackageName());
-            if (info == null) {
-                continue;
-            }
-            addIconToDBAndMemCache(app, info, userSerial);
+        if (!componentMap.isEmpty()) {
+            mWorkerHandler.post(new SerializedIconAdditionTask(userSerial, pkgInfoMap,
+                    componentMap.values()));
         }
         return updatedPackages;
     }
 
     private void addIconToDBAndMemCache(LauncherActivityInfoCompat app, PackageInfo info,
             long userSerial) {
-        ContentValues values = updateCacheAndGetContentValues(app);
+        // Reuse the existing entry if it already exists in the DB. This ensures that we do not
+        // create bitmap if it was already created during loader.
+        ContentValues values = updateCacheAndGetContentValues(app, false);
         addIconToDB(values, app.getComponentName(), info, userSerial);
-        values.put(IconDB.COLUMN_COMPONENT, app.getComponentName().flattenToString());
     }
 
     /**
@@ -327,9 +327,21 @@
                 SQLiteDatabase.CONFLICT_REPLACE);
     }
 
-    private ContentValues updateCacheAndGetContentValues(LauncherActivityInfoCompat app) {
-        CacheEntry entry = new CacheEntry();
-        entry.icon = Utilities.createIconBitmap(app.getBadgedIcon(mIconDpi), mContext);
+    private ContentValues updateCacheAndGetContentValues(LauncherActivityInfoCompat app,
+            boolean replaceExisting) {
+        final ComponentKey key = new ComponentKey(app.getComponentName(), app.getUser());
+        CacheEntry entry = null;
+        if (!replaceExisting) {
+            entry = mCache.get(key);
+            // We can't reuse the entry if the high-res icon is not present.
+            if (entry == null || entry.isLowResIcon || entry.icon == null) {
+                entry = null;
+            }
+        }
+        if (entry == null) {
+            entry = new CacheEntry();
+            entry.icon = Utilities.createIconBitmap(app.getBadgedIcon(mIconDpi), mContext);
+        }
         entry.title = app.getLabel();
         entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, app.getUser());
         mCache.put(new ComponentKey(app.getComponentName(), app.getUser()), entry);
@@ -671,6 +683,40 @@
         }
     }
 
+    /**
+     * A runnable that adds icons in the DB for the provided LauncherActivityInfoCompat list.
+     * Items are added one at a time, to that the worker thread does not get blocked.
+     */
+    private class SerializedIconAdditionTask implements Runnable {
+        private final long mUserSerial;
+        private final HashMap<String, PackageInfo> mPkgInfoMap;
+        private final Stack<LauncherActivityInfoCompat> mAppsToAdd;
+
+        private SerializedIconAdditionTask(long userSerial, HashMap<String, PackageInfo> pkgInfoMap,
+                Collection<LauncherActivityInfoCompat> appsToAdd) {
+            mUserSerial = userSerial;
+            mPkgInfoMap = pkgInfoMap;
+            mAppsToAdd = new Stack<LauncherActivityInfoCompat>();
+            mAppsToAdd.addAll(appsToAdd);
+        }
+
+        @Override
+        public void run() {
+            if (!mAppsToAdd.isEmpty()) {
+                LauncherActivityInfoCompat app = mAppsToAdd.pop();
+                PackageInfo info = mPkgInfoMap.get(app.getComponentName().getPackageName());
+                if (info != null) {
+                    synchronized (IconCache.this) {
+                        addIconToDBAndMemCache(app, info, mUserSerial);
+                    }
+                }
+            }
+            if (!mAppsToAdd.isEmpty()) {
+                mWorkerHandler.post(this);
+            }
+        }
+    }
+
     private static final class IconDB extends SQLiteOpenHelper {
         private final static int DB_VERSION = 4;
 
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 62f1bc9..dda9a16 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -633,9 +633,6 @@
             if (mCurrentPage != getNextPage()) {
                 AccessibilityEvent ev =
                         AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_SCROLLED);
-                ev.setItemCount(getChildCount());
-                ev.setFromIndex(getNextPage());
-                ev.setToIndex(getNextPage());
 
                 sendAccessibilityEventUnchecked(ev);
             }
@@ -912,8 +909,7 @@
                     pageGap = getPaddingRight();
                 }
 
-                childLeft += childWidth + pageGap
-                        + (lp.isFullScreenPage ? 0 : (getPaddingLeft() + getPaddingRight()));
+                childLeft += childWidth + pageGap + getChildGap();
             }
         }
 
@@ -961,6 +957,10 @@
         }
     }
 
+    protected int getChildGap() {
+        return 0;
+    }
+
     private void updateMaxScrollX() {
         int childCount = getChildCount();
         if (childCount > 0) {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 8c1c7d6..55742f6 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -89,10 +89,6 @@
         Insettable, UninstallSource, AccessibilityDragSource {
     private static final String TAG = "Launcher.Workspace";
 
-    private static final int CHILDREN_OUTLINE_FADE_OUT_DELAY = 0;
-    private static final int CHILDREN_OUTLINE_FADE_OUT_DURATION = 375;
-    private static final int CHILDREN_OUTLINE_FADE_IN_DURATION = 100;
-
     protected static final int SNAP_OFF_EMPTY_SCREEN_DURATION = 400;
     protected static final int FADE_EMPTY_SCREEN_DURATION = 150;
 
@@ -101,11 +97,6 @@
     static final boolean MAP_NO_RECURSE = false;
     static final boolean MAP_RECURSE = true;
 
-    // These animators are used to fade the children's outlines
-    private ObjectAnimator mChildrenOutlineFadeInAnimation;
-    private ObjectAnimator mChildrenOutlineFadeOutAnimation;
-    private float mChildrenOutlineAlpha = 0;
-
     private static final long CUSTOM_CONTENT_GESTURE_DELAY = 200;
     private long mTouchDownTime = -1;
     private long mCustomContentShowTime = -1;
@@ -388,7 +379,6 @@
         updateChildrenLayersEnabled(false);
         mLauncher.lockScreenOrientation();
         mLauncher.onInteractionBegin();
-        setChildrenBackgroundAlphaMultipliers(1f);
         // Prevent any Un/InstallShortcutReceivers from updating the db while we are dragging
         InstallShortcutReceiver.enableInstallQueue();
         post(new Runnable() {
@@ -578,7 +568,6 @@
     public void createCustomContentContainer() {
         CellLayout customScreen = (CellLayout)
                 mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, this, false);
-        customScreen.disableBackground();
         customScreen.disableDragTarget();
 
         mWorkspaceScreens.put(CUSTOM_CONTENT_SCREEN_ID, customScreen);
@@ -1533,45 +1522,12 @@
         }
     }
 
-    void showOutlines() {
-        if (!workspaceInModalState() && !mIsSwitchingState) {
-            if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
-            if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
-            mChildrenOutlineFadeInAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 1.0f);
-            mChildrenOutlineFadeInAnimation.setDuration(CHILDREN_OUTLINE_FADE_IN_DURATION);
-            mChildrenOutlineFadeInAnimation.start();
-        }
-    }
-
-    void hideOutlines() {
-        if (!workspaceInModalState() && !mIsSwitchingState) {
-            if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
-            if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
-            mChildrenOutlineFadeOutAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 0.0f);
-            mChildrenOutlineFadeOutAnimation.setDuration(CHILDREN_OUTLINE_FADE_OUT_DURATION);
-            mChildrenOutlineFadeOutAnimation.setStartDelay(CHILDREN_OUTLINE_FADE_OUT_DELAY);
-            mChildrenOutlineFadeOutAnimation.start();
-        }
-    }
-
     public void showOutlinesTemporarily() {
         if (!mIsPageMoving && !isTouchActive()) {
             snapToPage(mCurrentPage);
         }
     }
 
-    public void setChildrenOutlineAlpha(float alpha) {
-        mChildrenOutlineAlpha = alpha;
-        for (int i = 0; i < getChildCount(); i++) {
-            CellLayout cl = (CellLayout) getChildAt(i);
-            cl.setBackgroundAlpha(alpha);
-        }
-    }
-
-    public float getChildrenOutlineAlpha() {
-        return mChildrenOutlineAlpha;
-    }
-
     float backgroundAlphaInterpolator(float r) {
         float pivotA = 0.1f;
         float pivotB = 0.4f;
@@ -1601,13 +1557,6 @@
         }
     }
 
-    private void setChildrenBackgroundAlphaMultipliers(float a) {
-        for (int i = 0; i < getChildCount(); i++) {
-            CellLayout child = (CellLayout) getChildAt(i);
-            child.setBackgroundAlphaMultiplier(a);
-        }
-    }
-
     @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     @Override
     public void enableAccessibleDrag(boolean enable) {
@@ -2004,7 +1953,6 @@
 
     public void onStartReordering() {
         super.onStartReordering();
-        showOutlines();
         // Reordering handles its own animations, disable the automatic ones.
         disableLayoutTransitions();
     }
@@ -2017,7 +1965,6 @@
             return;
         }
 
-        hideOutlines();
         mScreenOrder.clear();
         int count = getChildCount();
         for (int i = 0; i < count; i++) {
@@ -2969,9 +2916,6 @@
 
         mSpringLoadedDragController.cancel();
 
-        if (!mIsPageMoving) {
-            hideOutlines();
-        }
         mLauncher.getDragLayer().hidePageHints();
     }
 
diff --git a/src/com/android/launcher3/model/WidgetsAndShortcutNameComparator.java b/src/com/android/launcher3/model/WidgetsAndShortcutNameComparator.java
index 7c4e806..61e8952 100644
--- a/src/com/android/launcher3/model/WidgetsAndShortcutNameComparator.java
+++ b/src/com/android/launcher3/model/WidgetsAndShortcutNameComparator.java
@@ -1,6 +1,5 @@
 package com.android.launcher3.model;
 
-import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
@@ -8,6 +7,7 @@
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.compat.AppWidgetManagerCompat;
+import com.android.launcher3.compat.UserHandleCompat;
 
 import java.text.Collator;
 import java.util.Comparator;
@@ -18,12 +18,14 @@
     private final PackageManager mPackageManager;
     private final HashMap<Object, String> mLabelCache;
     private final Collator mCollator;
+    private final UserHandleCompat mMainHandle;
 
     public WidgetsAndShortcutNameComparator(Context context) {
         mManager = AppWidgetManagerCompat.getInstance(context);
         mPackageManager = context.getPackageManager();
         mLabelCache = new HashMap<Object, String>();
         mCollator = Collator.getInstance();
+        mMainHandle = UserHandleCompat.myUserHandle();
     }
 
     @Override
@@ -45,19 +47,22 @@
                     : Utilities.trim(((ResolveInfo) b).loadLabel(mPackageManager));
             mLabelCache.put(b, labelB);
         }
-        int result = mCollator.compare(labelA, labelB);
-        if (result == 0 && a instanceof AppWidgetProviderInfo &&
-                b instanceof AppWidgetProviderInfo) {
-            AppWidgetProviderInfo aInfo = (AppWidgetProviderInfo) a;
-            AppWidgetProviderInfo bInfo = (AppWidgetProviderInfo) b;
 
-            // prioritize main user's widgets against work profile widgets.
-            if (aInfo.getProfile().equals(android.os.Process.myUserHandle())) {
-                return -1;
-            } else if (bInfo.getProfile().equals(android.os.Process.myUserHandle())) {
-                return 1;
-            }
+        // Currently, there is no work profile shortcuts, hence only considering the widget cases.
+
+        boolean aWorkProfile = (a instanceof LauncherAppWidgetProviderInfo) &&
+                !mMainHandle.equals(mManager.getUser((LauncherAppWidgetProviderInfo) a));
+        boolean bWorkProfile = (b instanceof LauncherAppWidgetProviderInfo) &&
+                !mMainHandle.equals(mManager.getUser((LauncherAppWidgetProviderInfo) b));
+
+        // Independent of how the labels compare, if only one of the two widget info belongs to
+        // work profile, put that one in the back.
+        if (aWorkProfile && !bWorkProfile) {
+            return 1;
         }
-        return result;
+        if (!aWorkProfile && bWorkProfile) {
+            return -1;
+        }
+        return mCollator.compare(labelA, labelB);
     }
 };
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
index 181c08a..7a7895f 100644
--- a/src/com/android/launcher3/widget/WidgetsContainerView.java
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -135,7 +135,7 @@
     //
 
     public View getContentView() {
-        return findViewById(R.id.widgets_content);
+        return mView;
     }
 
     public View getRevealView() {
diff --git a/src/com/android/launcher3/widget/WidgetsListAdapter.java b/src/com/android/launcher3/widget/WidgetsListAdapter.java
index 2f733dc..3916c00 100644
--- a/src/com/android/launcher3/widget/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/WidgetsListAdapter.java
@@ -183,7 +183,6 @@
         }
     }
 
-    @Override
     public boolean onFailedToRecycleView(WidgetsRowViewHolder holder) {
         // If child views are animating, then the RecyclerView may choose not to recycle the view,
         // causing extraneous onCreateViewHolder() calls.  It is safe in this case to continue