Merge "Changes to use new startTasks API" into sc-dev
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 5ffe315..0fe5432 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -120,7 +120,6 @@
                 getCurrentOverviewPage(launcher) < currentTaskAfterFlingForward));
 
         // Test opening a task.
-        startTestActivity(2);
         OverviewTask task = mLauncher.pressHome().switchToOverview().getCurrentTask();
         assertNotNull("overview.getCurrentTask() returned null (1)", task);
         assertNotNull("OverviewTask.open returned null", task.open());
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 986180c..9072907 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -95,6 +95,9 @@
     <!-- Tab label. A user can tap this tab to access their work widgets. [CHAR_LIMIT=25] -->
     <string name="widgets_full_sheet_work_tab">Work</string>
 
+    <!-- A widget category label for grouping widgets related to conversations. [CHAR_LIMIT=30] -->
+    <string name="widget_category_conversations">Conversations</string>
+
     <!-- All Apps -->
     <!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->
     <string name="all_apps_search_bar_hint">Search apps</string>
diff --git a/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java b/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java
index 8baf5a3..adf720f 100644
--- a/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java
+++ b/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java
@@ -35,6 +35,7 @@
 import android.content.pm.PackageInstaller;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
+import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
 
@@ -64,17 +65,11 @@
     private static final long OLD_WORK_PROFILE_ID = 11;
     private static final int WORK_PROFILE_ID = 10;
 
-    private static final int SYSTEM_USER = 0;
-    private static final int FLAG_SYSTEM = 0x00000800;
-    private static final int FLAG_PROFILE = 0x00001000;
-
     private ShadowUserManager mUserManager;
     private BackupManager mBackupManager;
     private LauncherModelHelper mModelHelper;
     private SQLiteDatabase mDb;
     private InvariantDeviceProfile mIdp;
-    private UserHandle mMainProfileUser;
-    private UserHandle mWorkProfileUser;
 
     @Before
     public void setUp() {
@@ -90,17 +85,15 @@
         final UserManager userManager = RuntimeEnvironment.application.getSystemService(
                 UserManager.class);
         mUserManager = Shadow.extract(userManager);
-        // sign in to primary user
-        mMainProfileUser = mUserManager.addUser(SYSTEM_USER, "me", FLAG_SYSTEM);
         // sign in to work profile
-        mWorkProfileUser = mUserManager.addUser(WORK_PROFILE_ID, "work", FLAG_PROFILE);
+        mUserManager.addUser(WORK_PROFILE_ID, "work", ShadowUserManager.FLAG_MANAGED_PROFILE);
     }
 
     private void setupBackupManager() {
         mBackupManager = new BackupManager(RuntimeEnvironment.application);
         final LShadowBackupManager bm = Shadow.extract(mBackupManager);
-        bm.addProfile(MY_OLD_PROFILE_ID, mMainProfileUser);
-        bm.addProfile(OLD_WORK_PROFILE_ID, mWorkProfileUser);
+        bm.addProfile(MY_OLD_PROFILE_ID, Process.myUserHandle());
+        bm.addProfile(OLD_WORK_PROFILE_ID, UserHandle.of(WORK_PROFILE_ID));
     }
 
     @Test
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 01f7c71..7496703 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -926,8 +926,7 @@
         if (disallowIntercept) {
             // We need to make sure to cancel our long press if
             // a scrollable widget takes over touch events
-            final View currentPage = getPageAt(mCurrentPage);
-            currentPage.cancelLongPress();
+            cancelCurrentPageLongPress();
         }
         super.requestDisallowInterceptTouchEvent(disallowIntercept);
     }
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index a1b7997..cf1cb45 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -78,7 +78,6 @@
 import com.android.launcher3.R;
 import com.android.launcher3.ShortcutAndWidgetContainer;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.Workspace;
 import com.android.launcher3.Workspace.ItemOperator;
 import com.android.launcher3.accessibility.AccessibleDragListenerAdapter;
 import com.android.launcher3.accessibility.FolderAccessibilityHelper;
@@ -534,9 +533,25 @@
     }
 
     private void startAnimation(final AnimatorSet a) {
-        final Workspace workspace = mLauncher.getWorkspace();
-        final CellLayout currentCellLayout =
-                (CellLayout) workspace.getChildAt(workspace.getCurrentPage());
+        mLauncher.getWorkspace().getVisiblePages()
+                .forEach(visiblePage -> addAnimatorListenerForPage(a, (CellLayout) visiblePage));
+
+        a.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mState = STATE_ANIMATING;
+                mCurrentAnimator = a;
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mCurrentAnimator = null;
+            }
+        });
+        a.start();
+    }
+
+    private void addAnimatorListenerForPage(AnimatorSet a, CellLayout currentCellLayout) {
         final boolean useHardware = shouldUseHardwareLayerForAnimation(currentCellLayout);
         final boolean wasHardwareAccelerated = currentCellLayout.isHardwareLayerEnabled();
 
@@ -546,8 +561,6 @@
                 if (useHardware) {
                     currentCellLayout.enableHardwareLayer(true);
                 }
-                mState = STATE_ANIMATING;
-                mCurrentAnimator = a;
             }
 
             @Override
@@ -555,10 +568,8 @@
                 if (useHardware) {
                     currentCellLayout.enableHardwareLayer(wasHardwareAccelerated);
                 }
-                mCurrentAnimator = null;
             }
         });
-        a.start();
     }
 
     private boolean shouldUseHardwareLayerForAnimation(CellLayout currentCellLayout) {
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 988794c..a2c0f5c 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -39,6 +39,7 @@
 
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.LauncherFiles;
+import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic;
@@ -304,6 +305,11 @@
         CacheEntry entry = getEntryForPackageLocked(
                 infoInOut.packageName, infoInOut.user, useLowResIcon);
         applyCacheEntry(entry, infoInOut);
+        if (infoInOut.category == PackageItemInfo.CONVERSATIONS) {
+            infoInOut.title = mContext.getString(R.string.widget_category_conversations);
+            infoInOut.contentDescription = mPackageManager.getUserBadgedLabel(
+                    infoInOut.title, infoInOut.user);
+        }
     }
 
     protected void applyCacheEntry(CacheEntry entry, ItemInfoWithIcon info) {
diff --git a/src/com/android/launcher3/model/data/PackageItemInfo.java b/src/com/android/launcher3/model/data/PackageItemInfo.java
index 7617d7e..a81fe6a 100644
--- a/src/com/android/launcher3/model/data/PackageItemInfo.java
+++ b/src/com/android/launcher3/model/data/PackageItemInfo.java
@@ -16,27 +16,47 @@
 
 package com.android.launcher3.model.data;
 
+import androidx.annotation.IntDef;
+
 import com.android.launcher3.LauncherSettings;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
 
 /**
  * Represents a {@link Package} in the widget tray section.
  */
 public class PackageItemInfo extends ItemInfoWithIcon {
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({NO_CATEGORY, CONVERSATIONS})
+    public @interface Category{}
+    /** The package is not categorized in the widget tray. */
+    public static final int NO_CATEGORY = 0;
+    /** The package is categorized to conversations widget in the widget tray. */
+    public static final int CONVERSATIONS = 1;
 
     /**
      * Package name of the {@link PackageItemInfo}.
      */
-    public String packageName;
+    public final String packageName;
+
+    /** Represents a widget category shown in the widget tray section. */
+    @Category public final int category;
 
     public PackageItemInfo(String packageName) {
+        this(packageName, NO_CATEGORY);
+    }
+
+    public PackageItemInfo(String packageName, @Category int category) {
         this.packageName = packageName;
+        this.category = category;
         this.itemType = LauncherSettings.Favorites.ITEM_TYPE_NON_ACTIONABLE;
     }
 
     public PackageItemInfo(PackageItemInfo copy) {
         this.packageName = copy.packageName;
+        this.category = copy.category;
         this.itemType = LauncherSettings.Favorites.ITEM_TYPE_NON_ACTIONABLE;
     }
 
diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
index f82f2cc..be18e54 100644
--- a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
+++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
@@ -36,6 +36,7 @@
 import com.android.launcher3.widget.picker.WidgetsDiffReporter;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -58,6 +59,9 @@
     private static final String TAG = "WidgetsModel";
     private static final boolean DEBUG = false;
 
+    private static final ComponentName CONVERSATION_WIDGET = ComponentName.createRelative(
+            "com.android.systemui", ".people.widget.PeopleSpaceWidgetProvider");
+
     /* Map of widgets and shortcuts that are tracked per package. */
     private final Map<PackageItemInfo, List<WidgetItem>> mWidgetsList = new HashMap<>();
 
@@ -156,7 +160,7 @@
 
         // Temporary list for {@link PackageItemInfos} to avoid having to go through
         // {@link mPackageItemInfos} to locate the key to be used for {@link #mWidgetsList}
-        HashMap<PackageUserKey, PackageItemInfo> tmpPackageItemInfos = new HashMap<>();
+        HashMap<WidgetPackageOrCategoryKey, PackageItemInfo> tmpPackageItemInfos = new HashMap<>();
 
         // Clear the lists only if this is an update on all widgets and shortcuts. If packageUser
         // isn't null, only updates the shortcuts and widgets for the app represented in
@@ -168,11 +172,11 @@
         mWidgetsList.putAll(rawWidgetsShortcuts.stream()
                 .filter(new WidgetValidityCheck(app))
                 .collect(Collectors.groupingBy(item -> {
-                    PackageUserKey packageUserKey = new PackageUserKey(
-                            item.componentName.getPackageName(), item.user);
+                    WidgetPackageOrCategoryKey packageUserKey = getWidgetPackageOrCategoryKey(item);
                     PackageItemInfo pInfo = tmpPackageItemInfos.get(packageUserKey);
                     if (pInfo == null) {
-                        pInfo = new PackageItemInfo(packageUserKey.mPackageName);
+                        pInfo = new PackageItemInfo(item.componentName.getPackageName(),
+                                packageUserKey.mCategory);
                         pInfo.user = item.user;
                         tmpPackageItemInfos.put(packageUserKey,  pInfo);
                     }
@@ -224,6 +228,13 @@
         return null;
     }
 
+    private WidgetPackageOrCategoryKey getWidgetPackageOrCategoryKey(WidgetItem item) {
+        if (CONVERSATION_WIDGET.equals(item.componentName)) {
+            return new WidgetPackageOrCategoryKey(PackageItemInfo.CONVERSATIONS, item.user);
+        }
+        return new WidgetPackageOrCategoryKey(item.componentName.getPackageName(), item.user);
+    }
+
     private static class WidgetValidityCheck implements Predicate<WidgetItem> {
 
         private final InvariantDeviceProfile mIdp;
@@ -265,4 +276,40 @@
             return true;
         }
     }
+
+    /** A hash key for grouping widgets by package name or category. */
+    private static class WidgetPackageOrCategoryKey {
+        /**
+         * The package name of the widget provider.
+         *
+         * <p>This shouldn't be empty if {@link #mCategory} has a value,
+         * {@link PackageItemInfo#NO_CATEGORY}.
+         */
+        public final String mPackage;
+        /** A widget category. */
+        @PackageItemInfo.Category public final int mCategory;
+        public final UserHandle mUser;
+        private final int mHashCode;
+
+        WidgetPackageOrCategoryKey(String packageName, UserHandle user) {
+            this(packageName,  PackageItemInfo.NO_CATEGORY, user);
+        }
+
+        WidgetPackageOrCategoryKey(@PackageItemInfo.Category int category, UserHandle user) {
+            this("", category, user);
+        }
+
+        private WidgetPackageOrCategoryKey(String packageName,
+                @PackageItemInfo.Category int category, UserHandle user) {
+            mPackage = packageName;
+            mCategory = category;
+            mUser = user;
+            mHashCode = Arrays.hashCode(new Object[]{mPackage, mCategory, mUser});
+        }
+
+        @Override
+        public int hashCode() {
+            return mHashCode;
+        }
+    }
 }
\ No newline at end of file