Merge "Allow user to place PendingAddShortcutInfo in opened Folder." into ub-launcher3-dorval-polish
diff --git a/res/layout/all_apps_discovery_item.xml b/res/layout/all_apps_discovery_item.xml
index 3350530..fb1755c 100644
--- a/res/layout/all_apps_discovery_item.xml
+++ b/res/layout/all_apps_discovery_item.xml
@@ -25,7 +25,9 @@
         android:layout_width="56dp"
         android:layout_height="56dp"
         android:padding="8dp"
-        android:scaleType="fitCenter"/>
+        android:scaleType="fitCenter"
+        android:focusable="false"
+        android:importantForAccessibility="no"/>
 
     <LinearLayout
         android:layout_width="match_parent"
diff --git a/res/layout/system_shortcut.xml b/res/layout/system_shortcut.xml
index 0952703..6f702f6 100644
--- a/res/layout/system_shortcut.xml
+++ b/res/layout/system_shortcut.xml
@@ -33,7 +33,8 @@
         android:textColor="?android:attr/textColorPrimary"
         android:fontFamily="sans-serif"
         launcher:iconDisplay="shortcut_popup"
-        launcher:layoutHorizontal="true" />
+        launcher:layoutHorizontal="true"
+        android:focusable="false" />
 
     <View
         android:id="@+id/icon"
diff --git a/res/values/config.xml b/res/values/config.xml
index ace1d7e..8f2590a 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -138,4 +138,5 @@
     <item type="id" name="action_move_screen_forwards" />
     <item type="id" name="action_resize" />
     <item type="id" name="action_deep_shortcuts" />
+    <item type="id" name="action_dismiss_notification" />
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f7c4825..3648e15 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -159,7 +159,7 @@
     <!-- Text for wallpaper change button -->
     <string name="wallpaper_button_text">Wallpapers</string>
     <!-- Text for settings button -->
-    <string name="settings_button_text">Settings</string>
+    <string name="settings_button_text">Home settings</string>
     <!-- Message shown when a feature is disabled by the administrator -->
     <string name="msg_disabled_by_admin">Disabled by your admin</string>
     <!-- Text for custom accessibility action to go to the overview mode, where users can look and change the overall UI of the launcher. -->
@@ -292,5 +292,13 @@
 
     <!-- Accessibility description for the shortcuts menu shown for an app. -->
     <string name="shortcuts_menu_description"><xliff:g id="number_of_shortcuts" example="3">%1$d</xliff:g> shortcuts for <xliff:g id="app_name" example="Messenger">%2$s</xliff:g></string>
+    <!-- Accessibility description when the shortcuts menu has notifications as well as shortcuts. -->
+    <string name="shortcuts_menu_with_notifications_description"><xliff:g id="number_of_shortcuts" example="3">%1$d</xliff:g> shortcuts and <xliff:g id="number_of_notifications" example="3">%2$d</xliff:g> notifications for <xliff:g id="app_name" example="Messenger">%3$s</xliff:g></string>
+
+    <!-- Accessibility action to dismiss a notification in the shortcuts menu for an icon. [CHAR_LIMIT=30] -->
+    <string name="action_dismiss_notification">Dismiss</string>
+
+    <!-- Accessibility confirmation for notification being dismissed. -->
+    <string name="notification_dismissed">Notification dismissed</string>
 
 </resources>
diff --git a/src/com/android/launcher3/AllAppsList.java b/src/com/android/launcher3/AllAppsList.java
index d7f0180..f3202be 100644
--- a/src/com/android/launcher3/AllAppsList.java
+++ b/src/com/android/launcher3/AllAppsList.java
@@ -42,15 +42,13 @@
     public static final int DEFAULT_APPLICATIONS_NUMBER = 42;
 
     /** The list off all apps. */
-    public ArrayList<AppInfo> data =
-            new ArrayList<AppInfo>(DEFAULT_APPLICATIONS_NUMBER);
+    public final ArrayList<AppInfo> data = new ArrayList<>(DEFAULT_APPLICATIONS_NUMBER);
     /** The list of apps that have been added since the last notify() call. */
-    public ArrayList<AppInfo> added =
-            new ArrayList<AppInfo>(DEFAULT_APPLICATIONS_NUMBER);
+    public ArrayList<AppInfo> added = new ArrayList<>(DEFAULT_APPLICATIONS_NUMBER);
     /** The list of apps that have been removed since the last notify() call. */
-    public ArrayList<AppInfo> removed = new ArrayList<AppInfo>();
+    public ArrayList<AppInfo> removed = new ArrayList<>();
     /** The list of apps that have been modified since the last notify() call. */
-    public ArrayList<AppInfo> modified = new ArrayList<AppInfo>();
+    public ArrayList<AppInfo> modified = new ArrayList<>();
 
     private IconCache mIconCache;
 
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 251f9d8..e49ead0 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -674,14 +674,6 @@
         }
     }
 
-    /**
-     * Returns true if the view can show custom shortcuts.
-     */
-    public boolean hasDeepShortcuts() {
-        return !mLauncher.getPopupDataProvider().getShortcutIdsForItem((ItemInfo) getTag())
-                .isEmpty();
-    }
-
     public int getIconSize() {
         return mIconSize;
     }
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index ce85570..b136e7d 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -34,6 +34,7 @@
 import android.text.TextUtils;
 import android.util.Base64;
 import android.util.Log;
+import android.util.Pair;
 
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.compat.UserManagerCompat;
@@ -59,6 +60,16 @@
 import java.util.Set;
 
 public class InstallShortcutReceiver extends BroadcastReceiver {
+
+    public static final int FLAG_ACTIVITY_PAUSED = 1;
+    public static final int FLAG_LOADER_RUNNING = 2;
+    public static final int FLAG_DRAG_AND_DROP = 4;
+    public static final int FLAG_BULK_ADD = 4;
+
+    // Determines whether to defer installing shortcuts immediately until
+    // processAllPendingInstalls() is called.
+    private static int sInstallQueueDisabledFlags = 0;
+
     private static final String TAG = "InstallShortcutReceiver";
     private static final boolean DBG = false;
 
@@ -151,10 +162,6 @@
         }
     }
 
-    // Determines whether to defer installing shortcuts immediately until
-    // processAllPendingInstalls() is called.
-    private static boolean mUseInstallQueue = false;
-
     public void onReceive(Context context, Intent data) {
         if (!ACTION_INSTALL_SHORTCUT.equals(data.getAction())) {
             return;
@@ -207,7 +214,7 @@
 
     public static ShortcutInfo fromShortcutIntent(Context context, Intent data) {
         PendingInstallShortcutInfo info = createPendingInfo(context, data);
-        return info == null ? null : (ShortcutInfo) info.getItemInfo();
+        return info == null ? null : (ShortcutInfo) info.getItemInfo().first;
     }
 
     public static void queueShortcut(ShortcutInfoCompat info, Context context) {
@@ -245,27 +252,28 @@
 
     private static void queuePendingShortcutInfo(PendingInstallShortcutInfo info, Context context) {
         // Queue the item up for adding if launcher has not loaded properly yet
-        LauncherAppState app = LauncherAppState.getInstance(context);
-        boolean launcherNotLoaded = app.getModel().getCallback() == null;
-
         addToInstallQueue(Utilities.getPrefs(context), info);
-        if (!mUseInstallQueue && !launcherNotLoaded) {
-            flushInstallQueue(context);
-        }
+        flushInstallQueue(context);
     }
 
-    static void enableInstallQueue() {
-        mUseInstallQueue = true;
+    public static void enableInstallQueue(int flag) {
+        sInstallQueueDisabledFlags |= flag;
     }
-    static void disableAndFlushInstallQueue(Context context) {
-        mUseInstallQueue = false;
+    public static void disableAndFlushInstallQueue(int flag, Context context) {
+        sInstallQueueDisabledFlags &= ~flag;
         flushInstallQueue(context);
     }
 
     static void flushInstallQueue(Context context) {
+        LauncherModel model = LauncherAppState.getInstance(context).getModel();
+        boolean launcherNotLoaded = model.getCallback() == null;
+        if (sInstallQueueDisabledFlags != 0 || launcherNotLoaded) {
+            return;
+        }
+
         ArrayList<PendingInstallShortcutInfo> items = getAndClearInstallQueue(context);
         if (!items.isEmpty()) {
-            LauncherAppState.getInstance(context).getModel().addAndBindAddedWorkspaceItems(
+            model.addAndBindAddedWorkspaceItems(
                     new LazyShortcutsProvider(context.getApplicationContext(), items));
         }
     }
@@ -439,7 +447,7 @@
             }
         }
 
-        public ItemInfo getItemInfo() {
+        public Pair<ItemInfo, Object> getItemInfo() {
             if (activityInfo != null) {
                 AppInfo appInfo = new AppInfo(mContext, activityInfo, user);
                 final LauncherAppState app = LauncherAppState.getInstance(mContext);
@@ -459,11 +467,11 @@
                         }
                     });
                 }
-                return si;
+                return Pair.create((ItemInfo) si, (Object) activityInfo);
             } else if (shortcutInfo != null) {
                 ShortcutInfo si = new ShortcutInfo(shortcutInfo, mContext);
                 si.iconBitmap = LauncherIcons.createShortcutIcon(shortcutInfo, mContext);
-                return si;
+                return Pair.create((ItemInfo) si, (Object) shortcutInfo);
             } else if (providerInfo != null) {
                 LauncherAppWidgetProviderInfo info = LauncherAppWidgetProviderInfo
                         .fromProviderInfo(mContext, providerInfo);
@@ -475,9 +483,10 @@
                 widgetInfo.minSpanY = info.minSpanY;
                 widgetInfo.spanX = Math.min(info.spanX, idp.numColumns);
                 widgetInfo.spanY = Math.min(info.spanY, idp.numRows);
-                return widgetInfo;
+                return Pair.create((ItemInfo) widgetInfo, (Object) providerInfo);
             } else {
-                return createShortcutInfo(data, LauncherAppState.getInstance(mContext));
+                ShortcutInfo si = createShortcutInfo(data, LauncherAppState.getInstance(mContext));
+                return Pair.create((ItemInfo) si, null);
             }
         }
 
@@ -588,7 +597,7 @@
         return new PendingInstallShortcutInfo(info, original.mContext);
     }
 
-    private static class LazyShortcutsProvider extends Provider<List<ItemInfo>> {
+    private static class LazyShortcutsProvider extends Provider<List<Pair<ItemInfo, Object>>> {
 
         private final Context mContext;
         private final ArrayList<PendingInstallShortcutInfo> mPendingItems;
@@ -603,9 +612,9 @@
          * packageManager and icon cache.
          */
         @Override
-        public ArrayList<ItemInfo> get() {
+        public ArrayList<Pair<ItemInfo, Object>> get() {
             Preconditions.assertNonUiThread();
-            ArrayList<ItemInfo> installQueue = new ArrayList<>();
+            ArrayList<Pair<ItemInfo, Object>> installQueue = new ArrayList<>();
             LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mContext);
             for (PendingInstallShortcutInfo pendingInfo : mPendingItems) {
                 // If the intent specifies a package, make sure the package exists
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index c5241d5..d3b4c94 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -91,7 +91,7 @@
 import com.android.launcher3.anim.AnimationLayerSet;
 import com.android.launcher3.compat.AppWidgetManagerCompat;
 import com.android.launcher3.compat.LauncherAppsCompat;
-import com.android.launcher3.compat.PinItemRequestCompat;
+import com.android.launcher3.compat.LauncherAppsCompatVO;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragLayer;
@@ -1038,13 +1038,12 @@
         updateInteraction(Workspace.State.NORMAL, mWorkspace.getState());
         mWorkspace.onResume();
 
-        if (!isWorkspaceLoading()) {
-            // Process any items that were added while Launcher was away.
-            InstallShortcutReceiver.disableAndFlushInstallQueue(this);
+        // Process any items that were added while Launcher was away.
+        InstallShortcutReceiver.disableAndFlushInstallQueue(
+                InstallShortcutReceiver.FLAG_ACTIVITY_PAUSED, this);
 
-            // Refresh shortcuts if the permission changed.
-            mModel.refreshShortcutsIfRequired();
-        }
+        // Refresh shortcuts if the permission changed.
+        mModel.refreshShortcutsIfRequired();
 
         if (shouldShowDiscoveryBounce()) {
             mAllAppsController.showDiscoveryBounce();
@@ -1059,7 +1058,7 @@
     @Override
     protected void onPause() {
         // Ensure that items added to Launcher are queued until Launcher returns
-        InstallShortcutReceiver.enableInstallQueue();
+        InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_ACTIVITY_PAUSED);
 
         super.onPause();
         mPaused = true;
@@ -1425,8 +1424,8 @@
 
         ShortcutInfo info = null;
         if (Utilities.isAtLeastO()) {
-            info = LauncherAppsCompat.createShortcutInfoFromPinItemRequest(
-                    this, PinItemRequestCompat.getPinItemRequest(data), 0);
+            info = LauncherAppsCompatVO.createShortcutInfoFromPinItemRequest(
+                    this, LauncherAppsCompatVO.getPinItemRequest(data), 0);
         }
 
         if (info == null) {
@@ -3676,7 +3675,8 @@
             mPendingActivityResult = null;
         }
 
-        InstallShortcutReceiver.disableAndFlushInstallQueue(this);
+        InstallShortcutReceiver.disableAndFlushInstallQueue(
+                InstallShortcutReceiver.FLAG_LOADER_RUNNING, this);
 
         NotificationListener.setNotificationsChangedListener(mPopupDataProvider);
 
@@ -4075,8 +4075,8 @@
             shortcutInfos.add(new KeyboardShortcutInfo(getString(R.string.custom_actions),
                     KeyEvent.KEYCODE_O, KeyEvent.META_CTRL_ON));
         }
-        if (currentFocus instanceof BubbleTextView &&
-                ((BubbleTextView) currentFocus).hasDeepShortcuts()) {
+        if (currentFocus.getTag() instanceof ItemInfo
+                && DeepShortcutManager.supportsShortcuts((ItemInfo) currentFocus.getTag())) {
             shortcutInfos.add(new KeyboardShortcutInfo(getString(R.string.action_deep_shortcut),
                     KeyEvent.KEYCODE_S, KeyEvent.META_CTRL_ON));
         }
diff --git a/src/com/android/launcher3/LauncherAppWidgetHostView.java b/src/com/android/launcher3/LauncherAppWidgetHostView.java
index 13cc7ba..c7b7782 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHostView.java
@@ -23,7 +23,6 @@
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.SystemClock;
-import android.util.Log;
 import android.util.SparseBooleanArray;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -40,9 +39,7 @@
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.dragndrop.DragLayer.TouchCompleteListener;
 
-import java.lang.reflect.Method;
 import java.util.ArrayList;
-import java.util.concurrent.Executor;
 
 /**
  * {@inheritDoc}
@@ -50,8 +47,6 @@
 public class LauncherAppWidgetHostView extends AppWidgetHostView
         implements TouchCompleteListener, View.OnLongClickListener {
 
-    private static final String TAG = "LauncherWidgetHostView";
-
     // Related to the auto-advancing of widgets
     private static final long ADVANCE_INTERVAL = 20000;
     private static final long ADVANCE_STAGGER = 250;
@@ -98,13 +93,7 @@
         setBackgroundResource(R.drawable.widget_internal_focus_bg);
 
         if (Utilities.isAtLeastO()) {
-            try {
-                Method asyncMethod = AppWidgetHostView.class
-                        .getMethod("setExecutor", Executor.class);
-                asyncMethod.invoke(this, Utilities.THREAD_POOL_EXECUTOR);
-            } catch (Exception e) {
-                Log.e(TAG, "Unable to set async executor", e);
-            }
+            setExecutor(Utilities.THREAD_POOL_EXECUTOR);
         }
     }
 
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index e75c217..b5ca301 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -40,6 +40,7 @@
 import android.util.Log;
 import android.util.LongSparseArray;
 import android.util.MutableInt;
+import android.util.Pair;
 
 import com.android.launcher3.compat.AppWidgetManagerCompat;
 import com.android.launcher3.compat.LauncherAppsCompat;
@@ -138,12 +139,6 @@
         }
     }
 
-    /**
-     * Set of runnables to be called on the background thread after the workspace binding
-     * is complete.
-     */
-    static final ArrayList<Runnable> mBindCompleteRunnables = new ArrayList<Runnable>();
-
     @Thunk WeakReference<Callbacks> mCallbacks;
 
     // < only access in worker thread >
@@ -251,15 +246,8 @@
     /**
      * Adds the provided items to the workspace.
      */
-    public void addAndBindAddedWorkspaceItems(List<ItemInfo> workspaceApps) {
-        addAndBindAddedWorkspaceItems(Provider.of(workspaceApps));
-    }
-
-    /**
-     * Adds the provided items to the workspace.
-     */
     public void addAndBindAddedWorkspaceItems(
-            Provider<List<ItemInfo>> appsProvider) {
+            Provider<List<Pair<ItemInfo, Object>>> appsProvider) {
         enqueueModelUpdateTask(new AddWorkspaceItemsTask(appsProvider));
     }
 
@@ -529,7 +517,7 @@
      */
     public boolean startLoader(int synchronousBindPage) {
         // Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems
-        InstallShortcutReceiver.enableInstallQueue();
+        InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_LOADER_RUNNING);
         synchronized (mLock) {
             // Don't bother to start the thread if we know it's not going to do anything
             if (mCallbacks != null && mCallbacks.get() != null) {
@@ -607,7 +595,6 @@
         private Context mContext;
         private int mPageToBindFirst;
 
-        @Thunk boolean mIsLoadingAndBindingWorkspace;
         private boolean mStopped;
 
         LoaderTask(Context context, int pageToBindFirst) {
@@ -675,8 +662,6 @@
             try {
                 long now = 0;
                 if (DEBUG_LOADERS) Log.d(TAG, "step 1.1: loading workspace");
-                // Set to false in bindWorkspace()
-                mIsLoadingAndBindingWorkspace = true;
                 loadWorkspace();
 
                 verifyNotStopped();
@@ -1584,18 +1569,6 @@
                         callbacks.finishBindingItems();
                     }
 
-                    mIsLoadingAndBindingWorkspace = false;
-
-                    // Run all the bind complete runnables after workspace is bound.
-                    if (!mBindCompleteRunnables.isEmpty()) {
-                        synchronized (mBindCompleteRunnables) {
-                            for (final Runnable r : mBindCompleteRunnables) {
-                                runOnWorkerThread(r);
-                            }
-                            mBindCompleteRunnables.clear();
-                        }
-                    }
-
                     // If we're profiling, ensure this is the last thing in the queue.
                     if (DEBUG_LOADERS) {
                         Log.d(TAG, "bound workspace in "
@@ -1710,31 +1683,7 @@
                     mBgAllAppsList.add(new AppInfo(app, user, quietMode), app);
                 }
 
-                final ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(mContext, user);
-                if (heuristic != null) {
-                    final Runnable r = new Runnable() {
-
-                        @Override
-                        public void run() {
-                            heuristic.processUserApps(apps);
-                        }
-                    };
-                    mUiExecutor.execute(new Runnable() {
-
-                                    @Override
-                                    public void run() {
-                                        // Check isLoadingWorkspace on the UI thread, as it is updated on
-                                        // the UI thread.
-                                        if (mIsLoadingAndBindingWorkspace) {
-                                            synchronized (mBindCompleteRunnables) {
-                                                mBindCompleteRunnables.add(r);
-                                            }
-                                        } else {
-                                            runOnWorkerThread(r);
-                                        }
-                                    }
-                                });
-                }
+                ManagedProfileHeuristic.onAllAppsLoaded(mContext, apps, user);
             }
 
             if (FeatureFlags.LAUNCHER3_PROMISE_APPS_IN_ALL_APPS) {
@@ -1768,8 +1717,6 @@
                     }
                 }
             });
-            // Cleanup any data stored for a deleted user.
-            ManagedProfileHeuristic.processAllUsers(profiles, mContext);
             if (DEBUG_LOADERS) {
                 Log.d(TAG, "Icons processed in "
                         + (SystemClock.uptimeMillis() - loadTime) + "ms");
@@ -1829,7 +1776,7 @@
                 CacheDataUpdatedTask.OP_CACHE_UPDATE, user, updatedPackages));
     }
 
-    void enqueueModelUpdateTask(BaseModelUpdateTask task) {
+    public void enqueueModelUpdateTask(BaseModelUpdateTask task) {
         if (!mModelLoaded && mLoaderTask == null) {
             if (DEBUG_LOADERS) {
                 Log.d(TAG, "enqueueModelUpdateTask Ignoring task since loader is pending=" + task);
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index c84a431..4813571 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3;
 
+import android.annotation.TargetApi;
 import android.appwidget.AppWidgetHost;
 import android.appwidget.AppWidgetManager;
 import android.content.ComponentName;
@@ -38,6 +39,7 @@
 import android.database.sqlite.SQLiteStatement;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
@@ -68,7 +70,6 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.lang.reflect.Method;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -855,15 +856,16 @@
          * Removes widgets which are registered to the Launcher's host, but are not present
          * in our model.
          */
+        @TargetApi(Build.VERSION_CODES.O)
         public void removeGhostWidgets(SQLiteDatabase db) {
             // Get all existing widget ids.
             final AppWidgetHost host = newLauncherWidgetHost();
             final int[] allWidgets;
             try {
-                Method getter = AppWidgetHost.class.getDeclaredMethod("getAppWidgetIds");
-                getter.setAccessible(true);
-                allWidgets = (int[]) getter.invoke(host);
-            } catch (Exception e) {
+                // Although the method was defined in O, it has existed since the beginning of time,
+                // so it might work on older platforms as well.
+                allWidgets = host.getAppWidgetIds();
+            } catch (IncompatibleClassChangeError e) {
                 Log.e(TAG, "getAppWidgetIds not supported", e);
                 return;
             }
diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java
index 61bcc17..8caba75 100644
--- a/src/com/android/launcher3/SessionCommitReceiver.java
+++ b/src/com/android/launcher3/SessionCommitReceiver.java
@@ -67,18 +67,19 @@
         SessionInfo info = intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION);
         UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
 
-        if (TextUtils.isEmpty(info.getAppPackageName()) ||
-                info.getInstallReason() != PackageManager.INSTALL_REASON_USER) {
-            return;
+        if (Process.myUserHandle().equals(user)) {
+            if (TextUtils.isEmpty(info.getAppPackageName()) ||
+                    info.getInstallReason() != PackageManager.INSTALL_REASON_USER) {
+                return;
+            }
         }
 
-        if (!Process.myUserHandle().equals(user)) {
-            // Managed profile is handled using ManagedProfileHeuristic
-            return;
-        }
+        queueAppIconAddition(context, info.getAppPackageName(), user);
+    }
 
+    public static void queueAppIconAddition(Context context, String packageName, UserHandle user) {
         List<LauncherActivityInfo> activities = LauncherAppsCompat.getInstance(context)
-                .getActivityList(info.getAppPackageName(), user);
+                .getActivityList(packageName, user);
         if (activities == null || activities.isEmpty()) {
             // no activity found
             return;
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 54e7dd2..b006453 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -259,7 +259,7 @@
         return scale;
     }
 
-    static boolean isSystemApp(Context context, Intent intent) {
+    public static boolean isSystemApp(Context context, Intent intent) {
         PackageManager pm = context.getPackageManager();
         ComponentName cn = intent.getComponent();
         String packageName = null;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index b3dd7ac..672203c 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -451,7 +451,7 @@
         mLauncher.lockScreenOrientation();
         mLauncher.onInteractionBegin();
         // Prevent any Un/InstallShortcutReceivers from updating the db while we are dragging
-        InstallShortcutReceiver.enableInstallQueue();
+        InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_DRAG_AND_DROP);
 
         // Do not add a new page if it is a accessible drag which was not started by the workspace.
         // We do not support accessibility drag from other sources and instead provide a direct
@@ -504,7 +504,8 @@
         mLauncher.unlockScreenOrientation(false);
 
         // Re-enable any Un/InstallShortcutReceiver and now process any queued items
-        InstallShortcutReceiver.disableAndFlushInstallQueue(getContext());
+        InstallShortcutReceiver.disableAndFlushInstallQueue(
+                InstallShortcutReceiver.FLAG_DRAG_AND_DROP, getContext());
 
         mOutlineProvider = null;
         mDragInfo = null;
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index e8127c4..3433533 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -36,6 +36,7 @@
 import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.popup.PopupContainerWithArrow;
+import com.android.launcher3.shortcuts.DeepShortcutManager;
 import com.android.launcher3.util.Thunk;
 
 import java.util.ArrayList;
@@ -103,8 +104,7 @@
 
         // If the request came from keyboard, do not add custom shortcuts as that is already
         // exposed as a direct shortcut
-        if (!fromKeyboard && host instanceof BubbleTextView
-                && ((BubbleTextView) host).hasDeepShortcuts()) {
+        if (!fromKeyboard && DeepShortcutManager.supportsShortcuts(item)) {
             info.addAction(mActions.get(DEEP_SHORTCUTS));
         }
 
diff --git a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
index 2ad0edb..8161219 100644
--- a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
@@ -18,6 +18,7 @@
 
 import android.view.View;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.ItemInfo;
@@ -25,6 +26,7 @@
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.R;
 import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.notification.NotificationMainView;
 import com.android.launcher3.shortcuts.DeepShortcutView;
 
 import java.util.ArrayList;
@@ -35,14 +37,23 @@
  */
 public class ShortcutMenuAccessibilityDelegate extends LauncherAccessibilityDelegate {
 
+    private static final int DISMISS_NOTIFICATION = R.id.action_dismiss_notification;
+
     public ShortcutMenuAccessibilityDelegate(Launcher launcher) {
         super(launcher);
+        mActions.put(DISMISS_NOTIFICATION, new AccessibilityAction(DISMISS_NOTIFICATION,
+                launcher.getText(R.string.action_dismiss_notification)));
     }
 
     @Override
     public void addSupportedActions(View host, AccessibilityNodeInfo info, boolean fromKeyboard) {
         if ((host.getParent() instanceof DeepShortcutView)) {
             info.addAction(mActions.get(ADD_TO_WORKSPACE));
+        } else if (host instanceof NotificationMainView) {
+            NotificationMainView notificationView = (NotificationMainView) host;
+            if (notificationView.canChildBeDismissed(notificationView)) {
+                info.addAction(mActions.get(DISMISS_NOTIFICATION));
+            }
         }
     }
 
@@ -73,6 +84,14 @@
                 onComplete.run();
             }
             return true;
+        } else if (action == DISMISS_NOTIFICATION) {
+            if (!(host instanceof NotificationMainView)) {
+                return false;
+            }
+            NotificationMainView notificationView = (NotificationMainView) host;
+            notificationView.onChildDismissed(notificationView);
+            announceConfirmation(R.string.notification_dismissed);
+            return true;
         }
         return false;
     }
diff --git a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
index 457b454..06097d0 100644
--- a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
+++ b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
@@ -54,7 +54,7 @@
         });
     }
 
-    protected ArrayList<ComponentKey> getTitleMatchResult(String query) {
+    public ArrayList<ComponentKey> getTitleMatchResult(String query) {
         // Do an intersection of the words in the query and each title, and filter out all the
         // apps that don't match all of the words in the query.
         final String queryTextLower = query.toLowerCase();
@@ -67,7 +67,7 @@
         return result;
     }
 
-    protected boolean matches(AppInfo info, String query) {
+    public boolean matches(AppInfo info, String query) {
         int queryLength = query.length();
 
         String title = info.title.toString();
diff --git a/src/com/android/launcher3/anim/RoundedRectRevealOutlineProvider.java b/src/com/android/launcher3/anim/RoundedRectRevealOutlineProvider.java
index a0d1f8b..9c09477 100644
--- a/src/com/android/launcher3/anim/RoundedRectRevealOutlineProvider.java
+++ b/src/com/android/launcher3/anim/RoundedRectRevealOutlineProvider.java
@@ -42,7 +42,7 @@
 
     @Override
     public boolean shouldRemoveElevationDuringAnimation() {
-        return true;
+        return false;
     }
 
     @Override
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompat.java b/src/com/android/launcher3/compat/LauncherAppsCompat.java
index 472cfc9..26f4ae7 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompat.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompat.java
@@ -26,13 +26,8 @@
 import android.os.UserHandle;
 import android.support.annotation.Nullable;
 
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherModel;
-import com.android.launcher3.ShortcutInfo;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.graphics.LauncherIcons;
 import com.android.launcher3.shortcuts.ShortcutInfoCompat;
-import com.android.launcher3.util.LooperExecutor;
 import com.android.launcher3.util.PackageUserKey;
 
 import java.util.List;
@@ -88,62 +83,6 @@
     public abstract List<ShortcutConfigActivityInfo> getCustomShortcutActivityList(
             @Nullable PackageUserKey packageUser);
 
-    /**
-     * request.accept() will initiate the following flow:
-     *      -> go-to-system-process for actual processing (a)
-     *      -> callback-to-launcher on UI thread (b)
-     *      -> post callback on the worker thread (c)
-     *      -> Update model and unpin (in system) any shortcut not in out model. (d)
-     *
-     * Note that (b) will take at-least one frame as it involves posting callback from binder
-     * thread to UI thread.
-     * If (d) happens before we add this shortcut to our model, we will end up unpinning
-     * the shortcut in the system.
-     * Here its the caller's responsibility to add the newly created ShortcutInfo immediately
-     * to the model (which may involves a single post-to-worker-thread). That will guarantee
-     * that (d) happens after model is updated.
-     */
-    @Nullable
-    public static ShortcutInfo createShortcutInfoFromPinItemRequest(
-            Context context, final PinItemRequestCompat request, final long acceptDelay) {
-        if (request != null &&
-                request.getRequestType() == PinItemRequestCompat.REQUEST_TYPE_SHORTCUT &&
-                request.isValid()) {
-
-            if (acceptDelay <= 0) {
-                if (!request.accept()) {
-                    return null;
-                }
-            } else {
-                // Block the worker thread until the accept() is called.
-                new LooperExecutor(LauncherModel.getWorkerLooper()).execute(new Runnable() {
-                    @Override
-                    public void run() {
-                        try {
-                            Thread.sleep(acceptDelay);
-                        } catch (InterruptedException e) {
-                            // Ignore
-                        }
-                        if (request.isValid()) {
-                            request.accept();
-                        }
-                    }
-                });
-            }
-
-            ShortcutInfoCompat compat = new ShortcutInfoCompat(request.getShortcutInfo());
-            ShortcutInfo info = new ShortcutInfo(compat, context);
-            // Apply the unbadged icon and fetch the actual icon asynchronously.
-            info.iconBitmap = LauncherIcons
-                    .createShortcutIcon(compat, context, false /* badged */);
-            LauncherAppState.getInstance(context).getModel()
-                    .updateAndBindShortcutInfo(info, compat);
-            return info;
-        } else {
-            return null;
-        }
-    }
-
     public void showAppDetailsForProfile(ComponentName component, UserHandle user) {
         showAppDetailsForProfile(component, user, null, null);
     }
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVO.java b/src/com/android/launcher3/compat/LauncherAppsCompatVO.java
index d145539..3214b46 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompatVO.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatVO.java
@@ -18,20 +18,27 @@
 
 import android.annotation.TargetApi;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.LauncherActivityInfo;
 import android.content.pm.LauncherApps;
+import android.content.pm.LauncherApps.PinItemRequest;
 import android.content.pm.PackageManager;
 import android.os.Build;
+import android.os.Parcelable;
 import android.os.Process;
 import android.os.UserHandle;
 import android.support.annotation.Nullable;
-import android.util.Log;
 
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel;
+import com.android.launcher3.ShortcutInfo;
 import com.android.launcher3.compat.ShortcutConfigActivityInfo.ShortcutConfigActivityInfoVO;
+import com.android.launcher3.graphics.LauncherIcons;
+import com.android.launcher3.shortcuts.ShortcutInfoCompat;
+import com.android.launcher3.util.LooperExecutor;
 import com.android.launcher3.util.PackageUserKey;
 
-import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -45,11 +52,6 @@
     @Override
     public ApplicationInfo getApplicationInfo(String packageName, int flags, UserHandle user) {
         try {
-            // TODO: Temporary workaround until the API signature is updated
-            if (false) {
-                throw new PackageManager.NameNotFoundException();
-            }
-
             ApplicationInfo info = mLauncherApps.getApplicationInfo(packageName, flags, user);
             return (info.flags & ApplicationInfo.FLAG_INSTALLED) == 0 || !info.enabled
                     ? null : info;
@@ -64,34 +66,89 @@
         List<ShortcutConfigActivityInfo> result = new ArrayList<>();
         UserHandle myUser = Process.myUserHandle();
 
-        try {
-            Method m = LauncherApps.class.getDeclaredMethod("getShortcutConfigActivityList",
-                    String.class, UserHandle.class);
-            final List<UserHandle> users;
-            final String packageName;
-            if (packageUser == null) {
-                users = UserManagerCompat.getInstance(mContext).getUserProfiles();
-                packageName = null;
-            } else {
-                users = new ArrayList<>(1);
-                users.add(packageUser.mUser);
-                packageName = packageUser.mPackageName;
-            }
-            for (UserHandle user : users) {
-                boolean ignoreTargetSdk = myUser.equals(user);
-                List<LauncherActivityInfo> activities =
-                        (List<LauncherActivityInfo>) m.invoke(mLauncherApps, packageName, user);
-                for (LauncherActivityInfo activityInfo : activities) {
-                    if (ignoreTargetSdk || activityInfo.getApplicationInfo().targetSdkVersion >=
-                            Build.VERSION_CODES.O) {
-                        result.add(new ShortcutConfigActivityInfoVO(activityInfo));
-                    }
+        final List<UserHandle> users;
+        final String packageName;
+        if (packageUser == null) {
+            users = UserManagerCompat.getInstance(mContext).getUserProfiles();
+            packageName = null;
+        } else {
+            users = new ArrayList<>(1);
+            users.add(packageUser.mUser);
+            packageName = packageUser.mPackageName;
+        }
+        for (UserHandle user : users) {
+            boolean ignoreTargetSdk = myUser.equals(user);
+            List<LauncherActivityInfo> activities =
+                    mLauncherApps.getShortcutConfigActivityList(packageName, user);
+            for (LauncherActivityInfo activityInfo : activities) {
+                if (ignoreTargetSdk || activityInfo.getApplicationInfo().targetSdkVersion >=
+                        Build.VERSION_CODES.O) {
+                    result.add(new ShortcutConfigActivityInfoVO(activityInfo));
                 }
             }
-        } catch (Exception e) {
-            Log.e("LauncherAppsCompatVO", "Error calling new API", e);
         }
 
         return result;
     }
+
+    /**
+     * request.accept() will initiate the following flow:
+     *      -> go-to-system-process for actual processing (a)
+     *      -> callback-to-launcher on UI thread (b)
+     *      -> post callback on the worker thread (c)
+     *      -> Update model and unpin (in system) any shortcut not in out model. (d)
+     *
+     * Note that (b) will take at-least one frame as it involves posting callback from binder
+     * thread to UI thread.
+     * If (d) happens before we add this shortcut to our model, we will end up unpinning
+     * the shortcut in the system.
+     * Here its the caller's responsibility to add the newly created ShortcutInfo immediately
+     * to the model (which may involves a single post-to-worker-thread). That will guarantee
+     * that (d) happens after model is updated.
+     */
+    @Nullable
+    public static ShortcutInfo createShortcutInfoFromPinItemRequest(
+            Context context, final PinItemRequest request, final long acceptDelay) {
+        if (request != null &&
+                request.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT &&
+                request.isValid()) {
+
+            if (acceptDelay <= 0) {
+                if (!request.accept()) {
+                    return null;
+                }
+            } else {
+                // Block the worker thread until the accept() is called.
+                new LooperExecutor(LauncherModel.getWorkerLooper()).execute(new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            Thread.sleep(acceptDelay);
+                        } catch (InterruptedException e) {
+                            // Ignore
+                        }
+                        if (request.isValid()) {
+                            request.accept();
+                        }
+                    }
+                });
+            }
+
+            ShortcutInfoCompat compat = new ShortcutInfoCompat(request.getShortcutInfo());
+            ShortcutInfo info = new ShortcutInfo(compat, context);
+            // Apply the unbadged icon and fetch the actual icon asynchronously.
+            info.iconBitmap = LauncherIcons
+                    .createShortcutIcon(compat, context, false /* badged */);
+            LauncherAppState.getInstance(context).getModel()
+                    .updateAndBindShortcutInfo(info, compat);
+            return info;
+        } else {
+            return null;
+        }
+    }
+
+    public static PinItemRequest getPinItemRequest(Intent intent) {
+        Parcelable extra = intent.getParcelableExtra(LauncherApps.EXTRA_PIN_ITEM_REQUEST);
+        return extra instanceof PinItemRequest ? (PinItemRequest) extra : null;
+    }
 }
diff --git a/src/com/android/launcher3/compat/PinItemRequestCompat.java b/src/com/android/launcher3/compat/PinItemRequestCompat.java
deleted file mode 100644
index 1308cba..0000000
--- a/src/com/android/launcher3/compat/PinItemRequestCompat.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2017 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.compat;
-
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ShortcutInfo;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.launcher3.Utilities;
-
-/**
- * A wrapper around platform implementation of PinItemRequestCompat until the
- * updated SDK is available.
- */
-public class PinItemRequestCompat implements Parcelable {
-
-    public static final String EXTRA_PIN_ITEM_REQUEST = "android.content.pm.extra.PIN_ITEM_REQUEST";
-
-    public static final int REQUEST_TYPE_SHORTCUT = 1;
-    public static final int REQUEST_TYPE_APPWIDGET = 2;
-
-    private final Parcelable mObject;
-
-    private PinItemRequestCompat(Parcelable object) {
-        mObject = object;
-    }
-
-    public int getRequestType() {
-        return (Integer) invokeMethod("getRequestType");
-    }
-
-    public ShortcutInfo getShortcutInfo() {
-        return (ShortcutInfo) invokeMethod("getShortcutInfo");
-    }
-
-    public AppWidgetProviderInfo getAppWidgetProviderInfo(Context context) {
-        try {
-            return (AppWidgetProviderInfo) mObject.getClass()
-                    .getDeclaredMethod("getAppWidgetProviderInfo", Context.class)
-                    .invoke(mObject, context);
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    public boolean isValid() {
-        return (Boolean) invokeMethod("isValid");
-    }
-
-    public boolean accept() {
-        return (Boolean) invokeMethod("accept");
-    }
-
-    public boolean accept(Bundle options) {
-        try {
-            return (Boolean) mObject.getClass().getDeclaredMethod("accept", Bundle.class)
-                    .invoke(mObject, options);
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    public Bundle getExtras() {
-        try {
-            return (Bundle) mObject.getClass().getDeclaredMethod("getExtras").invoke(mObject);
-        } catch (Exception e) {
-            return null;
-        }
-    }
-
-    private Object invokeMethod(String methodName) {
-        try {
-            return mObject.getClass().getDeclaredMethod(methodName).invoke(mObject);
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel parcel, int i) {
-        parcel.writeParcelable(mObject, i);
-    }
-
-    public static final Parcelable.Creator<PinItemRequestCompat> CREATOR =
-            new Parcelable.Creator<PinItemRequestCompat>() {
-                public PinItemRequestCompat createFromParcel(Parcel source) {
-                    Parcelable object = source.readParcelable(null);
-                    return new PinItemRequestCompat(object);
-                }
-
-                public PinItemRequestCompat[] newArray(int size) {
-                    return new PinItemRequestCompat[size];
-                }
-            };
-
-    public static PinItemRequestCompat getPinItemRequest(Intent intent) {
-        if (!Utilities.isAtLeastO()) {
-            return null;
-        }
-        Parcelable extra = intent.getParcelableExtra(EXTRA_PIN_ITEM_REQUEST);
-        return extra == null ? null : new PinItemRequestCompat(extra);
-    }
-}
diff --git a/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java b/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java
index 4a55e8c..6bdc627 100644
--- a/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java
+++ b/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java
@@ -37,8 +37,6 @@
 import com.android.launcher3.R;
 import com.android.launcher3.ShortcutInfo;
 
-import java.lang.reflect.Method;
-
 /**
  * Wrapper class for representing a shortcut configure activity.
  */
@@ -151,15 +149,13 @@
             if (getUser().equals(Process.myUserHandle())) {
                 return super.startConfigActivity(activity, requestCode);
             }
+            IntentSender is = activity.getSystemService(LauncherApps.class)
+                    .getShortcutConfigActivityIntent(mInfo);
             try {
-                Method m = LauncherApps.class.getDeclaredMethod(
-                        "getShortcutConfigActivityIntent", LauncherActivityInfo.class);
-                IntentSender is = (IntentSender) m.invoke(
-                        activity.getSystemService(LauncherApps.class), mInfo);
                 activity.startIntentSenderForResult(is, requestCode, null, 0, 0, 0);
                 return true;
-            } catch (Exception e) {
-                Log.e(TAG, "Error calling new API", e);
+            } catch (IntentSender.SendIntentException e) {
+                Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
                 return false;
             }
         }
diff --git a/src/com/android/launcher3/compat/UserManagerCompatVL.java b/src/com/android/launcher3/compat/UserManagerCompatVL.java
index 45525f5..c7f88f6 100644
--- a/src/com/android/launcher3/compat/UserManagerCompatVL.java
+++ b/src/com/android/launcher3/compat/UserManagerCompatVL.java
@@ -22,8 +22,8 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 
-import com.android.launcher3.Utilities;
 import com.android.launcher3.util.LongArrayMap;
+import com.android.launcher3.util.ManagedProfileHeuristic;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -122,7 +122,7 @@
 
     @Override
     public long getUserCreationTime(UserHandle user) {
-        SharedPreferences prefs = Utilities.getPrefs(mContext);
+        SharedPreferences prefs = ManagedProfileHeuristic.prefs(mContext);
         String key = USER_CREATION_TIME_KEY + getSerialNumberForUser(user);
         if (!prefs.contains(key)) {
             prefs.edit().putLong(key, System.currentTimeMillis()).apply();
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index 09592a8..29789c8 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -28,6 +28,7 @@
 import android.content.ClipData;
 import android.content.ClipDescription;
 import android.content.Intent;
+import android.content.pm.LauncherApps.PinItemRequest;
 import android.content.res.Configuration;
 import android.graphics.Canvas;
 import android.graphics.Point;
@@ -50,7 +51,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.compat.AppWidgetManagerCompat;
-import com.android.launcher3.compat.PinItemRequestCompat;
+import com.android.launcher3.compat.LauncherAppsCompatVO;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.shortcuts.ShortcutInfoCompat;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
@@ -60,7 +61,7 @@
 import com.android.launcher3.widget.WidgetHostViewLoader;
 import com.android.launcher3.widget.WidgetImageView;
 
-@TargetApi(Build.VERSION_CODES.N_MR1)
+@TargetApi(Build.VERSION_CODES.O)
 public class AddItemActivity extends BaseActivity implements OnLongClickListener, OnTouchListener {
 
     private static final int SHADOW_SIZE = 10;
@@ -70,7 +71,7 @@
 
     private final PointF mLastTouchPos = new PointF();
 
-    private PinItemRequestCompat mRequest;
+    private PinItemRequest mRequest;
     private LauncherAppState mApp;
     private InvariantDeviceProfile mIdp;
 
@@ -87,7 +88,7 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        mRequest = PinItemRequestCompat.getPinItemRequest(getIntent());
+        mRequest = LauncherAppsCompatVO.getPinItemRequest(getIntent());
         if (mRequest == null) {
             finish();
             return;
@@ -101,9 +102,9 @@
         mDeviceProfile = mIdp.getDeviceProfile(getApplicationContext());
 
         setContentView(R.layout.add_item_confirmation_activity);
-        mWidgetCell = (LivePreviewWidgetCell) findViewById(R.id.widget_cell);
+        mWidgetCell = findViewById(R.id.widget_cell);
 
-        if (mRequest.getRequestType() == PinItemRequestCompat.REQUEST_TYPE_SHORTCUT) {
+        if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT) {
             setupShortcut();
         } else {
             if (!setupWidget()) {
@@ -226,7 +227,7 @@
      * Called when place-automatically button is clicked.
      */
     public void onPlaceAutomaticallyClick(View v) {
-        if (mRequest.getRequestType() == PinItemRequestCompat.REQUEST_TYPE_SHORTCUT) {
+        if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT) {
             InstallShortcutReceiver.queueShortcut(
                     new ShortcutInfoCompat(mRequest.getShortcutInfo()), this);
             logCommand(Action.Command.CONFIRM);
diff --git a/src/com/android/launcher3/dragndrop/PinItemDragListener.java b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
index df0c47c..f9f4e50 100644
--- a/src/com/android/launcher3/dragndrop/PinItemDragListener.java
+++ b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
@@ -16,11 +16,14 @@
 
 package com.android.launcher3.dragndrop;
 
+import android.annotation.TargetApi;
 import android.appwidget.AppWidgetManager;
 import android.content.ClipDescription;
 import android.content.Intent;
+import android.content.pm.LauncherApps.PinItemRequest;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -40,7 +43,7 @@
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.PendingAddItemInfo;
 import com.android.launcher3.R;
-import com.android.launcher3.compat.PinItemRequestCompat;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -55,6 +58,7 @@
  * {@link DragSource} for handling drop from a different window. This object is initialized
  * in the source window and is passed on to the Launcher activity as an Intent extra.
  */
+@TargetApi(Build.VERSION_CODES.O)
 public class PinItemDragListener
         implements Parcelable, View.OnDragListener, DragSource, DragOptions.PreDragCondition {
 
@@ -63,7 +67,7 @@
     private static final String MIME_TYPE_PREFIX = "com.android.launcher3.drag_and_drop/";
     public static final String EXTRA_PIN_ITEM_DRAG_LISTENER = "pin_item_drag_listener";
 
-    private final PinItemRequestCompat mRequest;
+    private final PinItemRequest mRequest;
 
     // Position of preview relative to the touch location
     private final Rect mPreviewRect;
@@ -78,7 +82,7 @@
     private DragController mDragController;
     private long mDragStartTime;
 
-    public PinItemDragListener(PinItemRequestCompat request, Rect previewRect,
+    public PinItemDragListener(PinItemRequest request, Rect previewRect,
             int previewBitmapWidth, int previewViewWidth) {
         mRequest = request;
         mPreviewRect = previewRect;
@@ -88,7 +92,7 @@
     }
 
     private PinItemDragListener(Parcel parcel) {
-        mRequest = PinItemRequestCompat.CREATOR.createFromParcel(parcel);
+        mRequest = PinItemRequest.CREATOR.createFromParcel(parcel);
         mPreviewRect = Rect.CREATOR.createFromParcel(parcel);
         mPreviewBitmapWidth = parcel.readInt();
         mPreviewViewWidth = parcel.readInt();
@@ -146,7 +150,7 @@
         }
 
         final PendingAddItemInfo item;
-        if (mRequest.getRequestType() == PinItemRequestCompat.REQUEST_TYPE_SHORTCUT) {
+        if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT) {
             item = new PendingAddShortcutInfo(
                     new PinShortcutRequestActivityInfo(mRequest, mLauncher));
         } else {
@@ -177,7 +181,7 @@
         // across windows, using drag position here give a good estimate for relative position
         // to source window.
         PendingItemDragHelper dragHelper = new PendingItemDragHelper(view);
-        if (mRequest.getRequestType() == PinItemRequestCompat.REQUEST_TYPE_APPWIDGET) {
+        if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_APPWIDGET) {
             dragHelper.setPreview(getPreview(mRequest));
         }
 
@@ -271,7 +275,7 @@
         }
     }
 
-    public static RemoteViews getPreview(PinItemRequestCompat request) {
+    public static RemoteViews getPreview(PinItemRequest request) {
         Bundle extras = request.getExtras();
         if (extras != null &&
                 extras.get(AppWidgetManager.EXTRA_APPWIDGET_PREVIEW) instanceof RemoteViews) {
@@ -281,6 +285,9 @@
     }
 
     public static boolean handleDragRequest(Launcher launcher, Intent intent) {
+        if (!Utilities.isAtLeastO()) {
+            return false;
+        }
         if (intent == null || !Intent.ACTION_MAIN.equals(intent.getAction())) {
             return false;
         }
diff --git a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
index bb5ac5b..52abbc7 100644
--- a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
+++ b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
@@ -21,6 +21,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.LauncherApps;
+import android.content.pm.LauncherApps.PinItemRequest;
 import android.content.pm.ShortcutInfo;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
@@ -30,26 +31,25 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.R;
-import com.android.launcher3.compat.LauncherAppsCompat;
-import com.android.launcher3.compat.PinItemRequestCompat;
+import com.android.launcher3.compat.LauncherAppsCompatVO;
 import com.android.launcher3.compat.ShortcutConfigActivityInfo;
 
 /**
  * Extension of ShortcutConfigActivityInfo to be used in the confirmation prompt for pin item
  * request.
  */
-@TargetApi(Build.VERSION_CODES.N_MR1)
+@TargetApi(Build.VERSION_CODES.O)
 class PinShortcutRequestActivityInfo extends ShortcutConfigActivityInfo {
 
     // Class name used in the target component, such that it will never represent an
     // actual existing class.
     private static final String DUMMY_COMPONENT_CLASS = "pinned-shortcut";
 
-    private final PinItemRequestCompat mRequest;
+    private final PinItemRequest mRequest;
     private final ShortcutInfo mInfo;
     private final Context mContext;
 
-    public PinShortcutRequestActivityInfo(PinItemRequestCompat request, Context context) {
+    public PinShortcutRequestActivityInfo(PinItemRequest request, Context context) {
         super(new ComponentName(request.getShortcutInfo().getPackage(), DUMMY_COMPONENT_CLASS),
                 request.getShortcutInfo().getUserHandle());
         mRequest = request;
@@ -80,7 +80,7 @@
                 Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT +
                 mContext.getResources().getInteger(R.integer.config_overlayTransitionTime) / 2;
         // Delay the actual accept() call until the drop animation is complete.
-        return LauncherAppsCompat.createShortcutInfoFromPinItemRequest(
+        return LauncherAppsCompatVO.createShortcutInfoFromPinItemRequest(
                 mContext, mRequest, duration);
     }
 
diff --git a/src/com/android/launcher3/dragndrop/PinWidgetFlowHandler.java b/src/com/android/launcher3/dragndrop/PinWidgetFlowHandler.java
index b6da6ad..9f617e4 100644
--- a/src/com/android/launcher3/dragndrop/PinWidgetFlowHandler.java
+++ b/src/com/android/launcher3/dragndrop/PinWidgetFlowHandler.java
@@ -16,15 +16,17 @@
 
 package com.android.launcher3.dragndrop;
 
+import android.annotation.TargetApi;
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
+import android.content.pm.LauncherApps.PinItemRequest;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.Launcher;
-import com.android.launcher3.compat.PinItemRequestCompat;
 import com.android.launcher3.widget.WidgetAddFlowHandler;
 
 /**
@@ -33,18 +35,19 @@
  * No config activity is shown even if it is defined in widget config. And a callback is sent when
  * the widget is bound.
  */
+@TargetApi(Build.VERSION_CODES.O)
 public class PinWidgetFlowHandler extends WidgetAddFlowHandler implements Parcelable {
 
-    private final PinItemRequestCompat mRequest;
+    private final PinItemRequest mRequest;
 
-    public PinWidgetFlowHandler(AppWidgetProviderInfo providerInfo, PinItemRequestCompat request) {
+    public PinWidgetFlowHandler(AppWidgetProviderInfo providerInfo, PinItemRequest request) {
         super(providerInfo);
         mRequest = request;
     }
 
     protected PinWidgetFlowHandler(Parcel parcel) {
         super(parcel);
-        mRequest = PinItemRequestCompat.CREATOR.createFromParcel(parcel);
+        mRequest = PinItemRequest.CREATOR.createFromParcel(parcel);
     }
 
     @Override
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index 10fb582..2e8e15b 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -17,6 +17,8 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.LauncherActivityInfo;
+import android.os.Process;
 import android.os.UserHandle;
 import android.util.LongSparseArray;
 import android.util.Pair;
@@ -35,9 +37,11 @@
 import com.android.launcher3.ShortcutInfo;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.util.GridOccupancy;
+import com.android.launcher3.util.ManagedProfileHeuristic.UserFolderInfo;
 import com.android.launcher3.util.Provider;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 
 /**
@@ -45,18 +49,18 @@
  */
 public class AddWorkspaceItemsTask extends ExtendedModelTask {
 
-    private final Provider<List<ItemInfo>> mAppsProvider;
+    private final Provider<List<Pair<ItemInfo, Object>>> mAppsProvider;
 
     /**
      * @param appsProvider items to add on the workspace
      */
-    public AddWorkspaceItemsTask(Provider<List<ItemInfo>> appsProvider) {
+    public AddWorkspaceItemsTask(Provider<List<Pair<ItemInfo, Object>>> appsProvider) {
         mAppsProvider = appsProvider;
     }
 
     @Override
     public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
-        List<ItemInfo> workspaceApps = mAppsProvider.get();
+        List<Pair<ItemInfo, Object>> workspaceApps = mAppsProvider.get();
         if (workspaceApps.isEmpty()) {
             return;
         }
@@ -64,13 +68,17 @@
 
         final ArrayList<ItemInfo> addedItemsFinal = new ArrayList<>();
         final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<>();
+        HashMap<UserHandle, UserFolderInfo> userFolderMap = new HashMap<>();
 
         // Get the list of workspace screens.  We need to append to this list and
         // can not use sBgWorkspaceScreens because loadWorkspace() may not have been
         // called.
         ArrayList<Long> workspaceScreens = LauncherModel.loadWorkspaceScreensDb(context);
         synchronized(dataModel) {
-            for (ItemInfo item : workspaceApps) {
+
+            List<ItemInfo> filteredItems = new ArrayList<>();
+            for (Pair<ItemInfo, Object> entry : workspaceApps) {
+                ItemInfo item = entry.first;
                 if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
                         item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
                     // Short-circuit this logic if the icon exists somewhere on the workspace
@@ -79,6 +87,32 @@
                     }
                 }
 
+                if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
+                    if (item instanceof AppInfo) {
+                        item = ((AppInfo) item).makeShortcut();
+                    }
+
+                    if (!Process.myUserHandle().equals(item.user)) {
+                        // Check if this belongs to a work folder.
+                        if (!(entry.second instanceof LauncherActivityInfo)) {
+                            continue;
+                        }
+
+                        UserFolderInfo userFolderInfo = userFolderMap.get(item.user);
+                        if (userFolderInfo == null) {
+                            userFolderInfo = new UserFolderInfo(context, item.user, dataModel);
+                            userFolderMap.put(item.user, userFolderInfo);
+                        }
+                        item = userFolderInfo.convertToWorkspaceItem(
+                                (ShortcutInfo) item, (LauncherActivityInfo) entry.second);
+                    }
+                }
+                if (item != null) {
+                    filteredItems.add(item);
+                }
+            }
+
+            for (ItemInfo item : filteredItems) {
                 // Find appropriate space for the item.
                 Pair<Long, int[]> coords = findSpaceForItem(app, dataModel, workspaceScreens,
                         addedWorkspaceScreensFinal, item.spanX, item.spanY);
@@ -130,6 +164,10 @@
                 }
             });
         }
+
+        for (UserFolderInfo userFolderInfo : userFolderMap.values()) {
+            userFolderInfo.applyPendingState(getModelWriter());
+        }
     }
 
     protected void updateScreens(Context context, ArrayList<Long> workspaceScreens) {
@@ -276,4 +314,5 @@
         }
         return occupied.findVacantCell(xy, spanX, spanY);
     }
+
 }
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index b58efb6..8380f01 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -35,6 +35,7 @@
 import com.android.launcher3.LauncherModel.Callbacks;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.SessionCommitReceiver;
 import com.android.launcher3.ShortcutInfo;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.compat.LauncherAppsCompat;
@@ -43,7 +44,6 @@
 import com.android.launcher3.graphics.LauncherIcons;
 import com.android.launcher3.util.FlagOp;
 import com.android.launcher3.util.ItemInfoMatcher;
-import com.android.launcher3.util.ManagedProfileHeuristic;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.PackageUserKey;
 
@@ -100,11 +100,11 @@
                         appsList.removePackage(packages[i], Process.myUserHandle());
                     }
                     appsList.addPackage(context, packages[i], mUser);
-                }
 
-                ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(context, mUser);
-                if (heuristic != null) {
-                    heuristic.processPackageAdd(mPackages);
+                    // Automatically add homescreen icon for work profile apps for below O device.
+                    if (!Utilities.isAtLeastO() && !Process.myUserHandle().equals(mUser)) {
+                        SessionCommitReceiver.queueAppIconAddition(context, packages[i], mUser);
+                    }
                 }
                 break;
             }
@@ -119,10 +119,6 @@
                 flagOp = FlagOp.removeFlag(ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE);
                 break;
             case OP_REMOVE: {
-                ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(context, mUser);
-                if (heuristic != null) {
-                    heuristic.processPackageRemoved(mPackages);
-                }
                 for (int i = 0; i < N; i++) {
                     iconCache.removeIconsForPkg(packages[i], mUser);
                 }
diff --git a/src/com/android/launcher3/notification/NotificationFooterLayout.java b/src/com/android/launcher3/notification/NotificationFooterLayout.java
index 1eef743..051c033 100644
--- a/src/com/android/launcher3/notification/NotificationFooterLayout.java
+++ b/src/com/android/launcher3/notification/NotificationFooterLayout.java
@@ -141,6 +141,7 @@
         icon.setBackground(info.getIconForBackground(getContext(), mBackgroundColor));
         icon.setOnClickListener(info);
         icon.setTag(info);
+        icon.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
         mIconRow.addView(icon, 0, mIconLayoutParams);
         return icon;
     }
diff --git a/src/com/android/launcher3/notification/NotificationItemView.java b/src/com/android/launcher3/notification/NotificationItemView.java
index dd272b3..997def2 100644
--- a/src/com/android/launcher3/notification/NotificationItemView.java
+++ b/src/com/android/launcher3/notification/NotificationItemView.java
@@ -77,6 +77,10 @@
         mSwipeHelper.setDisableHardwareLayers(true);
     }
 
+    public NotificationMainView getMainView() {
+        return mMainView;
+    }
+
     public int getHeightMinusFooter() {
         int footerHeight = mFooter.getParent() == null ? 0 : mFooter.getHeight();
         return getHeight() - footerHeight;
diff --git a/src/com/android/launcher3/notification/NotificationMainView.java b/src/com/android/launcher3/notification/NotificationMainView.java
index d6e0272..0d6da77 100644
--- a/src/com/android/launcher3/notification/NotificationMainView.java
+++ b/src/com/android/launcher3/notification/NotificationMainView.java
@@ -122,7 +122,7 @@
 
     @Override
     public boolean canChildBeDismissed(View v) {
-        return mNotificationInfo.dismissable;
+        return mNotificationInfo != null && mNotificationInfo.dismissable;
     }
 
     @Override
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index d4ee3b8..ccead37 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -114,7 +114,6 @@
 
         mStartDragThreshold = getResources().getDimensionPixelSize(
                 R.dimen.deep_shortcuts_start_drag_threshold);
-        // TODO: make sure the delegate works for all items, not just shortcuts.
         mAccessibilityDelegate = new ShortcutMenuAccessibilityDelegate(mLauncher);
         mIsRtl = Utilities.isRtl(getResources());
     }
@@ -176,7 +175,7 @@
         // Add dummy views first, and populate with real info when ready.
         PopupPopulator.Item[] itemsToPopulate = PopupPopulator
                 .getItemsToPopulate(shortcutIds, notificationKeys, systemShortcuts);
-        addDummyViews(originalIcon, itemsToPopulate, notificationKeys.size() > 1);
+        addDummyViews(itemsToPopulate, notificationKeys.size() > 1);
 
         measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
         orientAboutIcon(originalIcon, arrowHeight + arrowVerticalOffset);
@@ -187,7 +186,7 @@
             mNotificationItemView = null;
             mShortcutsItemView = null;
             itemsToPopulate = PopupPopulator.reverseItems(itemsToPopulate);
-            addDummyViews(originalIcon, itemsToPopulate, notificationKeys.size() > 1);
+            addDummyViews(itemsToPopulate, notificationKeys.size() > 1);
 
             measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
             orientAboutIcon(originalIcon, arrowHeight + arrowVerticalOffset);
@@ -204,6 +203,17 @@
             updateNotificationHeader();
         }
 
+        int numShortcuts = shortcutViews.size() + systemShortcutViews.size();
+        int numNotifications = notificationKeys.size();
+        if (numNotifications == 0) {
+            setContentDescription(getContext().getString(R.string.shortcuts_menu_description,
+                    numShortcuts, originalIcon.getContentDescription().toString()));
+        } else {
+            setContentDescription(getContext().getString(
+                    R.string.shortcuts_menu_with_notifications_description, numShortcuts,
+                    numNotifications, originalIcon.getContentDescription().toString()));
+        }
+
         // Add the arrow.
         final int arrowHorizontalOffset = resources.getDimensionPixelSize(isAlignedWithStart() ?
                 R.dimen.popup_arrow_horizontal_offset_start :
@@ -225,8 +235,8 @@
                 systemShortcuts, systemShortcutViews));
     }
 
-    private void addDummyViews(BubbleTextView originalIcon,
-            PopupPopulator.Item[] itemTypesToPopulate, boolean notificationFooterHasIcons) {
+    private void addDummyViews(PopupPopulator.Item[] itemTypesToPopulate,
+            boolean notificationFooterHasIcons) {
         final Resources res = getResources();
         final int spacing = res.getDimensionPixelSize(R.dimen.popup_items_spacing);
         final LayoutInflater inflater = mLauncher.getLayoutInflater();
@@ -243,12 +253,14 @@
                 int footerHeight = notificationFooterHasIcons ?
                         res.getDimensionPixelSize(R.dimen.notification_footer_height) : 0;
                 item.findViewById(R.id.footer).getLayoutParams().height = footerHeight;
+                mNotificationItemView.getMainView().setAccessibilityDelegate(mAccessibilityDelegate);
+            } else if (itemTypeToPopulate == PopupPopulator.Item.SHORTCUT) {
+                item.setAccessibilityDelegate(mAccessibilityDelegate);
             }
 
             boolean shouldAddBottomMargin = nextItemTypeToPopulate != null
                     && itemTypeToPopulate.isShortcut ^ nextItemTypeToPopulate.isShortcut;
 
-            item.setAccessibilityDelegate(mAccessibilityDelegate);
             if (itemTypeToPopulate.isShortcut) {
                 if (mShortcutsItemView == null) {
                     mShortcutsItemView = (ShortcutsItemView) inflater.inflate(
@@ -266,9 +278,6 @@
                 }
             }
         }
-        // TODO: update this, since not all items are shortcuts
-        setContentDescription(getContext().getString(R.string.shortcuts_menu_description,
-                numItems, originalIcon.getContentDescription().toString()));
     }
 
     protected PopupItemView getItemViewAt(int index) {
diff --git a/src/com/android/launcher3/util/CachedPackageTracker.java b/src/com/android/launcher3/util/CachedPackageTracker.java
deleted file mode 100644
index 314b4c0..0000000
--- a/src/com/android/launcher3/util/CachedPackageTracker.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2016 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.Context;
-import android.content.SharedPreferences;
-import android.content.pm.LauncherActivityInfo;
-import android.os.UserHandle;
-
-import com.android.launcher3.Utilities;
-import com.android.launcher3.compat.LauncherAppsCompat;
-import com.android.launcher3.compat.LauncherAppsCompat.OnAppsChangedCallbackCompat;
-import com.android.launcher3.compat.UserManagerCompat;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Utility class to track list of installed packages. It persists the list so that apps
- * installed/uninstalled while Launcher was dead can also be handled properly.
- */
-public abstract class CachedPackageTracker implements OnAppsChangedCallbackCompat {
-
-    protected static final String INSTALLED_PACKAGES_PREFIX = "installed_packages_for_user_";
-
-    protected final SharedPreferences mPrefs;
-    protected final UserManagerCompat mUserManager;
-    protected final LauncherAppsCompat mLauncherApps;
-
-    public CachedPackageTracker(Context context, String preferenceFileName) {
-        mPrefs = context.getSharedPreferences(preferenceFileName, Context.MODE_PRIVATE);
-        mUserManager = UserManagerCompat.getInstance(context);
-        mLauncherApps = LauncherAppsCompat.getInstance(context);
-    }
-
-    /**
-     * Checks the list of user apps, and generates package event accordingly.
-     * {@see #onLauncherAppsAdded}, {@see #onLauncherPackageRemoved}
-     */
-    public void processUserApps(List<LauncherActivityInfo> apps, UserHandle user) {
-        String prefKey = INSTALLED_PACKAGES_PREFIX + mUserManager.getSerialNumberForUser(user);
-        HashSet<String> oldPackageSet = new HashSet<>();
-        final boolean userAppsExisted = getUserApps(oldPackageSet, prefKey);
-
-        HashSet<String> packagesRemoved = new HashSet<>(oldPackageSet);
-        HashSet<String> newPackageSet = new HashSet<>();
-        ArrayList<LauncherActivityInstallInfo> packagesAdded = new ArrayList<>();
-
-        for (LauncherActivityInfo info : apps) {
-            String packageName = info.getComponentName().getPackageName();
-            newPackageSet.add(packageName);
-            packagesRemoved.remove(packageName);
-
-            if (!oldPackageSet.contains(packageName)) {
-                oldPackageSet.add(packageName);
-                packagesAdded.add(new LauncherActivityInstallInfo(
-                        info, info.getFirstInstallTime()));
-            }
-        }
-
-        if (!packagesAdded.isEmpty() || !packagesRemoved.isEmpty()) {
-            mPrefs.edit().putStringSet(prefKey, newPackageSet).apply();
-
-            if (!packagesAdded.isEmpty()) {
-                Collections.sort(packagesAdded);
-                onLauncherAppsAdded(packagesAdded, user, userAppsExisted);
-            }
-
-            if (!packagesRemoved.isEmpty()) {
-                for (String pkg : packagesRemoved) {
-                    onLauncherPackageRemoved(pkg, user);
-                }
-            }
-        }
-    }
-
-    /**
-     * Reads the list of user apps which have already been processed.
-     * @return false if the list didn't exist, true otherwise
-     */
-    private boolean getUserApps(HashSet<String> outExistingApps, String prefKey) {
-        Set<String> userApps = mPrefs.getStringSet(prefKey, null);
-        if (userApps == null) {
-            return false;
-        } else {
-            outExistingApps.addAll(userApps);
-            return true;
-        }
-    }
-
-    @Override
-    public void onPackageRemoved(String packageName, UserHandle user) {
-        String prefKey = INSTALLED_PACKAGES_PREFIX + mUserManager.getSerialNumberForUser(user);
-        HashSet<String> packageSet = new HashSet<>();
-        if (getUserApps(packageSet, prefKey) && packageSet.remove(packageName)) {
-            mPrefs.edit().putStringSet(prefKey, packageSet).apply();
-        }
-
-        onLauncherPackageRemoved(packageName, user);
-    }
-
-    @Override
-    public void onPackageAdded(String packageName, UserHandle user) {
-        String prefKey = INSTALLED_PACKAGES_PREFIX + mUserManager.getSerialNumberForUser(user);
-        HashSet<String> packageSet = new HashSet<>();
-        final boolean userAppsExisted = getUserApps(packageSet, prefKey);
-        if (!packageSet.contains(packageName)) {
-            List<LauncherActivityInfo> activities =
-                    mLauncherApps.getActivityList(packageName, user);
-            if (!activities.isEmpty()) {
-                LauncherActivityInfo activityInfo = activities.get(0);
-
-                packageSet.add(packageName);
-                mPrefs.edit().putStringSet(prefKey, packageSet).apply();
-                onLauncherAppsAdded(Arrays.asList(
-                        new LauncherActivityInstallInfo(activityInfo, System.currentTimeMillis())),
-                        user, userAppsExisted);
-            }
-        }
-    }
-
-    @Override
-    public void onPackageChanged(String packageName, UserHandle user) { }
-
-    @Override
-    public void onPackagesAvailable(
-            String[] packageNames, UserHandle user, boolean replacing) { }
-
-    @Override
-    public void onPackagesUnavailable(
-            String[] packageNames, UserHandle user, boolean replacing) { }
-
-    @Override
-    public void onPackagesSuspended(String[] packageNames, UserHandle user) { }
-
-    @Override
-    public void onPackagesUnsuspended(String[] packageNames, UserHandle user) { }
-
-    /**
-     * Called when new launcher apps are added.
-     * @param apps list of newly added activities. Only one entry per package is sent.
-     * @param user the user for this event. All activities in {@param apps} will belong to
-     *             the same user.
-     * @param userAppsExisted false if the list was processed for the first time, like in case
-     *                        when Launcher was newly installed or a new user was added.
-     */
-    protected abstract void onLauncherAppsAdded(List<LauncherActivityInstallInfo> apps,
-            UserHandle user, boolean userAppsExisted);
-
-    /**
-     * Called when apps are removed from the system.
-     */
-    protected abstract void onLauncherPackageRemoved(String packageName, UserHandle user);
-
-    public static class LauncherActivityInstallInfo
-            implements Comparable<LauncherActivityInstallInfo> {
-        public final LauncherActivityInfo info;
-        public final long installTime;
-
-        public LauncherActivityInstallInfo(LauncherActivityInfo info, long installTime) {
-            this.info = info;
-            this.installTime = installTime;
-        }
-
-        @Override
-        public int compareTo(LauncherActivityInstallInfo another) {
-            return Utilities.longCompare(installTime, another.installTime);
-        }
-    }
-}
diff --git a/src/com/android/launcher3/util/ManagedProfileHeuristic.java b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
index ce603c4..091dd84 100644
--- a/src/com/android/launcher3/util/ManagedProfileHeuristic.java
+++ b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
@@ -19,23 +19,23 @@
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.content.pm.LauncherActivityInfo;
+import android.os.Handler;
 import android.os.Process;
 import android.os.UserHandle;
-import android.support.v4.os.BuildCompat;
 
-import com.android.launcher3.AppInfo;
 import com.android.launcher3.FolderInfo;
-import com.android.launcher3.IconCache;
+import com.android.launcher3.InstallShortcutReceiver;
 import com.android.launcher3.ItemInfo;
-import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherFiles;
 import com.android.launcher3.LauncherModel;
 import com.android.launcher3.MainThreadExecutor;
 import com.android.launcher3.R;
 import com.android.launcher3.SessionCommitReceiver;
 import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.compat.UserManagerCompat;
-import com.android.launcher3.shortcuts.ShortcutInfoCompat;
+import com.android.launcher3.model.BgDataModel;
+import com.android.launcher3.model.ModelWriter;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -47,11 +47,6 @@
  */
 public class ManagedProfileHeuristic {
 
-    /**
-     * Maintain a set of packages installed per user.
-     */
-    private static final String INSTALLED_PACKAGES_PREFIX = "installed_packages_for_user_";
-
     private static final String USER_FOLDER_ID_PREFIX = "user_folder_";
 
     /**
@@ -59,165 +54,154 @@
      */
     private static final long AUTO_ADD_TO_FOLDER_DURATION = 8 * 60 * 60 * 1000;
 
-    public static ManagedProfileHeuristic get(Context context, UserHandle user) {
-        if (!Process.myUserHandle().equals(user)) {
-            return new ManagedProfileHeuristic(context, user);
-        }
-        return null;
-    }
-
-    private final Context mContext;
-    private final LauncherModel mModel;
-    private final UserHandle mUser;
-    private final IconCache mIconCache;
-    private final boolean mAddIconsToHomescreen;
-
-    private ManagedProfileHeuristic(Context context, UserHandle user) {
-        mContext = context;
-        mUser = user;
-        mModel = LauncherAppState.getInstance(context).getModel();
-        mIconCache = LauncherAppState.getInstance(context).getIconCache();
-        mAddIconsToHomescreen =
-                !BuildCompat.isAtLeastO() || SessionCommitReceiver.isEnabled(context);
-    }
-
-    public void processPackageRemoved(String[] packages) {
-        Preconditions.assertWorkerThread();
-        ManagedProfilePackageHandler handler = new ManagedProfilePackageHandler();
-        for (String pkg : packages) {
-            handler.onPackageRemoved(pkg, mUser);
-        }
-    }
-
-    public void processPackageAdd(String[] packages) {
-        Preconditions.assertWorkerThread();
-        ManagedProfilePackageHandler handler = new ManagedProfilePackageHandler();
-        for (String pkg : packages) {
-            handler.onPackageAdded(pkg, mUser);
-        }
-    }
-
-    public void processUserApps(List<LauncherActivityInfo> apps) {
-        Preconditions.assertWorkerThread();
-        new ManagedProfilePackageHandler().processUserApps(apps, mUser);
-    }
-
-    private class ManagedProfilePackageHandler extends CachedPackageTracker {
-
-        private ManagedProfilePackageHandler() {
-            super(mContext, LauncherFiles.MANAGED_USER_PREFERENCES_KEY);
+    public static void onAllAppsLoaded(final Context context,
+            List<LauncherActivityInfo> apps, UserHandle user) {
+        if (Process.myUserHandle().equals(user)) {
+            return;
         }
 
-        protected void onLauncherAppsAdded(
-                List<LauncherActivityInstallInfo> apps, UserHandle user, boolean userAppsExisted) {
-            ArrayList<ShortcutInfo> workFolderApps = new ArrayList<>();
-            ArrayList<ShortcutInfo> homescreenApps = new ArrayList<>();
+        UserFolderInfo ufi = new UserFolderInfo(context, user, null);
+        // We only handle folder creation once. Later icon additions are handled using package
+        // or session events.
+        if (ufi.folderAlreadyCreated) {
+            return;
+        }
 
-            int count = apps.size();
-            long folderCreationTime =
-                    mUserManager.getUserCreationTime(user) + AUTO_ADD_TO_FOLDER_DURATION;
+        if (Utilities.isAtLeastO() && !SessionCommitReceiver.isEnabled(context)) {
+            // Just mark the folder id preference to avoid new folder creation later.
+            ufi.prefs.edit().putLong(ufi.folderIdKey, ItemInfo.NO_ID).apply();
+            return;
+        }
 
-            boolean quietModeEnabled = UserManagerCompat.getInstance(mContext)
-                    .isQuietModeEnabled(user);
-            for (int i = 0; i < count; i++) {
-                LauncherActivityInstallInfo info = apps.get(i);
-                AppInfo appInfo = new AppInfo(info.info, user, quietModeEnabled);
-                mIconCache.getTitleAndIcon(appInfo, info.info, false /* useLowResIcon */);
-                ShortcutInfo si = appInfo.makeShortcut();
-                ((info.installTime <= folderCreationTime) ? workFolderApps : homescreenApps).add(si);
-            }
-
-            finalizeWorkFolder(user, workFolderApps, homescreenApps);
-
-            // Do not add shortcuts on the homescreen for the first time. This prevents the launcher
-            // getting filled with the managed user apps, when it start with a fresh DB (or after
-            // a very long time).
-            if (userAppsExisted && !homescreenApps.isEmpty() && mAddIconsToHomescreen) {
-                mModel.addAndBindAddedWorkspaceItems(new ArrayList<ItemInfo>(homescreenApps));
+        InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_BULK_ADD);
+        for (LauncherActivityInfo app : apps) {
+            // Queue all items which should go in the work folder.
+            if (app.getFirstInstallTime() < ufi.addIconToFolderTime) {
+                InstallShortcutReceiver.queueActivityInfo(app, context);
             }
         }
+        // Post the queue update on next frame, so that the loader gets finished.
+        new Handler(LauncherModel.getWorkerLooper()).post(new Runnable() {
+            @Override
+            public void run() {
+                InstallShortcutReceiver.disableAndFlushInstallQueue(
+                        InstallShortcutReceiver.FLAG_BULK_ADD, context);
+            }
+        });
+    }
 
-        @Override
-        protected void onLauncherPackageRemoved(String packageName, UserHandle user) {
+
+    /**
+     * Utility class to help workspace icon addition.
+     */
+    public static class UserFolderInfo {
+
+        final ArrayList<ShortcutInfo> pendingShortcuts = new ArrayList<>();
+
+        final UserHandle user;
+
+        final long userSerial;
+        // Time until which icons will be added to folder instead.
+        final long addIconToFolderTime;
+
+        final String folderIdKey;
+        final SharedPreferences prefs;
+
+        final boolean folderAlreadyCreated;
+        final FolderInfo folderInfo;
+
+        boolean folderPendingAddition;
+
+        public UserFolderInfo(Context context, UserHandle user, BgDataModel dataModel) {
+            this.user = user;
+
+            UserManagerCompat um = UserManagerCompat.getInstance(context);
+            userSerial = um.getSerialNumberForUser(user);
+            addIconToFolderTime = um.getUserCreationTime(user) + AUTO_ADD_TO_FOLDER_DURATION;
+
+            folderIdKey = USER_FOLDER_ID_PREFIX + userSerial;
+            prefs = prefs(context);
+
+            folderAlreadyCreated = prefs.contains(folderIdKey);
+            if (dataModel != null) {
+                if (folderAlreadyCreated) {
+                    long folderId = prefs.getLong(folderIdKey, ItemInfo.NO_ID);
+                    folderInfo = dataModel.folders.get(folderId);
+                } else {
+                    folderInfo = new FolderInfo();
+                    folderInfo.title = context.getText(R.string.work_folder_name);
+                    folderInfo.setOption(FolderInfo.FLAG_WORK_FOLDER, true, null);
+                    folderPendingAddition = true;
+                }
+            } else {
+                folderInfo = null;
+            }
         }
 
         /**
-         * Adds and binds shortcuts marked to be added to the work folder.
+         * Returns the ItemInfo which should be added to the workspace. In case the the provided
+         * {@link ShortcutInfo} or a wrapped {@link FolderInfo} or null.
          */
-        private void finalizeWorkFolder(
-                UserHandle user, final ArrayList<ShortcutInfo> workFolderApps,
-                ArrayList<ShortcutInfo> homescreenApps) {
-            if (workFolderApps.isEmpty()) {
+        public ItemInfo convertToWorkspaceItem(
+                ShortcutInfo shortcut, LauncherActivityInfo activityInfo) {
+            if (activityInfo.getFirstInstallTime() >= addIconToFolderTime) {
+                return shortcut;
+            }
+
+            if (folderAlreadyCreated) {
+                if (folderInfo == null) {
+                    // Work folder was deleted by user, add icon to home screen.
+                    return shortcut;
+                } else {
+                    // Add item to work folder instead. Nothing needs to be added
+                    // on the homescreen.
+                    pendingShortcuts.add(shortcut);
+                    return null;
+                }
+            }
+
+            pendingShortcuts.add(shortcut);
+            folderInfo.add(shortcut, false);
+            if (folderPendingAddition) {
+                folderPendingAddition = false;
+                return folderInfo;
+            } else {
+                // WorkFolder already requested to be added. Nothing new needs to be added.
+                return null;
+            }
+        }
+
+        public void applyPendingState(ModelWriter writer) {
+            if (folderInfo == null) {
                 return;
             }
-            // Try to get a work folder.
-            String folderIdKey = USER_FOLDER_ID_PREFIX + mUserManager.getSerialNumberForUser(user);
-            if (!mAddIconsToHomescreen) {
-                if (!mPrefs.contains(folderIdKey)) {
-                    // Just mark the folder id preference to avoid new folder creation later.
-                    mPrefs.edit().putLong(folderIdKey, -1).apply();
-                }
-                return;
+
+            int startingRank = 0;
+            if (folderAlreadyCreated) {
+                startingRank = folderInfo.contents.size();
             }
-            if (mPrefs.contains(folderIdKey)) {
-                long folderId = mPrefs.getLong(folderIdKey, 0);
-                final FolderInfo workFolder = mModel.findFolderById(folderId);
 
-                if (workFolder == null || !workFolder.hasOption(FolderInfo.FLAG_WORK_FOLDER)) {
-                    // Could not get a work folder. Add all the icons to homescreen.
-                    homescreenApps.addAll(0, workFolderApps);
-                    return;
-                }
-                saveWorkFolderShortcuts(folderId, workFolder.contents.size(), workFolderApps);
+            for (ShortcutInfo info : pendingShortcuts) {
+                info.rank = startingRank++;
+                writer.addItemToDatabase(info, folderInfo.id, 0, 0, 0);
+            }
 
+            if (folderAlreadyCreated) {
                 // FolderInfo could already be bound. We need to add shortcuts on the UI thread.
                 new MainThreadExecutor().execute(new Runnable() {
 
                     @Override
                     public void run() {
-                        workFolder.prepareAutoUpdate();
-                        for (ShortcutInfo info : workFolderApps) {
-                            workFolder.add(info, false);
+                        folderInfo.prepareAutoUpdate();
+                        for (ShortcutInfo info : pendingShortcuts) {
+                            folderInfo.add(info, false);
                         }
                     }
                 });
             } else {
-                // Create a new folder.
-                final FolderInfo workFolder = new FolderInfo();
-                workFolder.title = mContext.getText(R.string.work_folder_name);
-                workFolder.setOption(FolderInfo.FLAG_WORK_FOLDER, true, null);
-
-                // Add all shortcuts before adding it to the UI, as an empty folder might get deleted.
-                for (ShortcutInfo info : workFolderApps) {
-                    workFolder.add(info, false);
-                }
-
-                // Add the item to home screen and DB. This also generates an item id synchronously.
-                ArrayList<ItemInfo> itemList = new ArrayList<>(1);
-                itemList.add(workFolder);
-                mModel.addAndBindAddedWorkspaceItems(itemList);
-                mPrefs.edit().putLong(folderIdKey, workFolder.id).apply();
-
-                saveWorkFolderShortcuts(workFolder.id, 0, workFolderApps);
+                prefs.edit().putLong(folderIdKey, folderInfo.id).apply();
             }
         }
-
-        @Override
-        public void onShortcutsChanged(String packageName, List<ShortcutInfoCompat> shortcuts,
-                UserHandle user) {
-            // Do nothing
-        }
-    }
-
-    /**
-     * Add work folder shortcuts to the DB.
-     */
-    private void saveWorkFolderShortcuts(
-            long workFolderId, int startingRank, ArrayList<ShortcutInfo> workFolderApps) {
-        for (ItemInfo info : workFolderApps) {
-            info.rank = startingRank++;
-            mModel.getWriter(false).addItemToDatabase(info, workFolderId, 0, 0, 0);
-        }
     }
 
     /**
@@ -225,14 +209,12 @@
      */
     public static void processAllUsers(List<UserHandle> users, Context context) {
         UserManagerCompat userManager = UserManagerCompat.getInstance(context);
-        HashSet<String> validKeys = new HashSet<String>();
+        HashSet<String> validKeys = new HashSet<>();
         for (UserHandle user : users) {
-            addAllUserKeys(userManager.getSerialNumberForUser(user), validKeys);
+            validKeys.add(USER_FOLDER_ID_PREFIX + userManager.getSerialNumberForUser(user));
         }
 
-        SharedPreferences prefs = context.getSharedPreferences(
-                LauncherFiles.MANAGED_USER_PREFERENCES_KEY,
-                Context.MODE_PRIVATE);
+        SharedPreferences prefs = prefs(context);
         SharedPreferences.Editor editor = prefs.edit();
         for (String key : prefs.getAll().keySet()) {
             if (!validKeys.contains(key)) {
@@ -242,11 +224,6 @@
         editor.apply();
     }
 
-    private static void addAllUserKeys(long userSerial, HashSet<String> keysOut) {
-        keysOut.add(INSTALLED_PACKAGES_PREFIX + userSerial);
-        keysOut.add(USER_FOLDER_ID_PREFIX + userSerial);
-    }
-
     /**
      * For each user, if a work folder has not been created, mark it such that the folder will
      * never get created.
@@ -260,11 +237,8 @@
             if (myUser.equals(user)) {
                 continue;
             }
-
             if (prefs == null) {
-                prefs = context.getSharedPreferences(
-                        LauncherFiles.MANAGED_USER_PREFERENCES_KEY,
-                        Context.MODE_PRIVATE);
+                prefs = prefs(context);
             }
             String folderIdKey = USER_FOLDER_ID_PREFIX + userManager.getSerialNumberForUser(user);
             if (!prefs.contains(folderIdKey)) {
@@ -272,4 +246,9 @@
             }
         }
     }
+
+    public static SharedPreferences prefs(Context context) {
+        return context.getSharedPreferences(
+                LauncherFiles.MANAGED_USER_PREFERENCES_KEY, Context.MODE_PRIVATE);
+    }
 }
diff --git a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
index 883be5a..4c80902 100644
--- a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
+++ b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
@@ -21,6 +21,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.verify;
@@ -50,7 +51,11 @@
     }
 
     private AddWorkspaceItemsTask newTask(ItemInfo... items) {
-        return new AddWorkspaceItemsTask(Provider.of(Arrays.asList(items))) {
+        List<Pair<ItemInfo, Object>> list = new ArrayList<>();
+        for (ItemInfo item : items) {
+            list.add(Pair.create(item, null));
+        }
+        return new AddWorkspaceItemsTask(Provider.of(list)) {
 
             @Override
             protected void updateScreens(Context context, ArrayList<Long> workspaceScreens) { }