Merge "Cancelling launcher reload on mcc change" into ub-launcher3-burnaby
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index 1c917bf..6500ebc 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -34,6 +34,7 @@
             android:layout_height="52dp" />
 
         <!-- The workspace contains 5 screens of cells -->
+        <!-- DO NOT CHANGE THE ID -->
         <com.android.launcher3.Workspace
             android:id="@+id/workspace"
             android:layout_width="match_parent"
@@ -41,6 +42,7 @@
             android:layout_gravity="center"
             launcher:defaultScreen="@integer/config_workspaceDefaultScreen" />
 
+        <!-- DO NOT CHANGE THE ID -->
         <include layout="@layout/hotseat"
             android:id="@+id/hotseat"
             android:layout_width="match_parent"
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index 8ff7762..d0772ee 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -35,6 +35,7 @@
             android:layout_height="52dp" />
 
         <!-- The workspace contains 5 screens of cells -->
+        <!-- DO NOT CHANGE THE ID -->
         <com.android.launcher3.Workspace
             android:id="@+id/workspace"
             android:layout_width="match_parent"
@@ -43,6 +44,7 @@
             launcher:pageIndicator="@+id/page_indicator">
         </com.android.launcher3.Workspace>
 
+        <!-- DO NOT CHANGE THE ID -->
         <include layout="@layout/hotseat"
             android:id="@+id/hotseat"
             android:layout_width="match_parent"
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml
index b27f33b..d382c6a 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout-sw720dp/launcher.xml
@@ -35,6 +35,7 @@
             android:layout_height="52dp" />
 
         <!-- The workspace contains 5 screens of cells -->
+        <!-- DO NOT CHANGE THE ID -->
         <com.android.launcher3.Workspace
             android:id="@+id/workspace"
             android:layout_width="match_parent"
@@ -43,6 +44,7 @@
             launcher:pageIndicator="@id/page_indicator">
         </com.android.launcher3.Workspace>
 
+        <!-- DO NOT CHANGE THE ID -->
         <include layout="@layout/hotseat"
             android:id="@+id/hotseat"
             android:layout_width="match_parent"
@@ -58,8 +60,7 @@
 
         <!-- Keep these behind the workspace so that they are not visible when
              we go into AllApps -->
-        <include
-            android:id="@+id/page_indicator"
+        <include android:id="@+id/page_indicator"
             layout="@layout/page_indicator"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
diff --git a/res/layout/all_apps_container.xml b/res/layout/all_apps_container.xml
index 5801a0e..1de8201 100644
--- a/res/layout/all_apps_container.xml
+++ b/res/layout/all_apps_container.xml
@@ -24,8 +24,9 @@
     android:focusable="true"
     android:focusableInTouchMode="true">
 
+    <!-- DO NOT CHANGE THE ID -->
     <com.android.launcher3.allapps.AllAppsRecyclerView
-        android:id="@+id/collection"
+        android:id="@+id/apps_list_view"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_gravity="center_horizontal|top"
diff --git a/res/layout/widgets_view.xml b/res/layout/widgets_view.xml
index c27e79b..161c268 100644
--- a/res/layout/widgets_view.xml
+++ b/res/layout/widgets_view.xml
@@ -37,6 +37,7 @@
             android:elevation="2dp"
             android:visibility="invisible" />
 
+        <!-- DO NOT CHANGE THE ID -->
         <com.android.launcher3.widget.WidgetsRecyclerView
             android:id="@+id/widgets_list_view"
             android:layout_width="match_parent"
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 3596b71..a75a09a 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -93,17 +93,16 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 import android.widget.Toast;
-
 import com.android.launcher3.DropTarget.DragObject;
 import com.android.launcher3.PagedView.PageSwitchListener;
 import com.android.launcher3.allapps.AllAppsContainerView;
-import com.android.launcher3.allapps.AllAppsSearchBarController;
 import com.android.launcher3.compat.AppWidgetManagerCompat;
 import com.android.launcher3.compat.LauncherActivityInfoCompat;
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.model.WidgetsModel;
+import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.LongArrayMap;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
@@ -3448,7 +3447,7 @@
      */
     private void tryAndUpdatePredictedApps() {
         if (mLauncherCallbacks != null) {
-            List<ComponentName> apps = mLauncherCallbacks.getPredictedApps();
+            List<ComponentKey> apps = mLauncherCallbacks.getPredictedApps();
             if (!apps.isEmpty()) {
                 mAppsView.setPredictedApps(apps);
             }
diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java
index e732754..56db774 100644
--- a/src/com/android/launcher3/LauncherCallbacks.java
+++ b/src/com/android/launcher3/LauncherCallbacks.java
@@ -8,6 +8,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import com.android.launcher3.allapps.AllAppsSearchBarController;
+import com.android.launcher3.util.ComponentKey;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -92,7 +93,7 @@
     public boolean overrideWallpaperDimensions();
     public boolean isLauncherPreinstalled();
     public AllAppsSearchBarController getAllAppsSearchBarController();
-    public List<ComponentName> getPredictedApps();
+    public List<ComponentKey> getPredictedApps();
 
     /**
      * Returning true will immediately result in a call to {@link #setLauncherOverlayView(ViewGroup,
diff --git a/src/com/android/launcher3/LauncherExtension.java b/src/com/android/launcher3/LauncherExtension.java
index fafb070..857ec57 100644
--- a/src/com/android/launcher3/LauncherExtension.java
+++ b/src/com/android/launcher3/LauncherExtension.java
@@ -12,6 +12,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import com.android.launcher3.allapps.AllAppsSearchBarController;
+import com.android.launcher3.util.ComponentKey;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -253,7 +254,7 @@
         }
 
         @Override
-        public List<ComponentName> getPredictedApps() {
+        public List<ComponentKey> getPredictedApps() {
             return new ArrayList<>();
         }
 
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 0fbe8e9..d56e9fc 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -207,7 +207,7 @@
     /**
      * Sets the current set of predicted apps.
      */
-    public void setPredictedApps(List<ComponentName> apps) {
+    public void setPredictedApps(List<ComponentKey> apps) {
         mApps.setPredictedApps(apps);
     }
 
@@ -328,7 +328,7 @@
         mRevealView = findViewById(R.id.all_apps_reveal);
 
         // Load the all apps recycler view
-        mAppsRecyclerView = (AllAppsRecyclerView) findViewById(R.id.collection);
+        mAppsRecyclerView = (AllAppsRecyclerView) findViewById(R.id.apps_list_view);
         mAppsRecyclerView.setApps(mApps);
         mAppsRecyclerView.setPredictionBarHeight(mPredictionBarHeight);
         mAppsRecyclerView.setLayoutManager(mLayoutManager);
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index b7b6ed7..aa73c74 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -15,14 +15,14 @@
  */
 package com.android.launcher3.allapps;
 
-import android.content.ComponentName;
 import android.content.Context;
 import android.support.v7.widget.RecyclerView;
 import android.util.Log;
-
 import com.android.launcher3.AppInfo;
 import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.compat.AlphabeticIndexCompat;
+import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.model.AppNameComparator;
 import com.android.launcher3.util.ComponentKey;
 
@@ -159,7 +159,7 @@
     // The set of sections that we allow fast-scrolling to (includes non-merged sections)
     private List<FastScrollSectionInfo> mFastScrollerSections = new ArrayList<>();
     // The set of predicted app component names
-    private List<ComponentName> mPredictedAppComponents = new ArrayList<>();
+    private List<ComponentKey> mPredictedAppComponents = new ArrayList<>();
     // The set of predicted apps resolved from the component names and the current set of apps
     private List<AppInfo> mPredictedApps = new ArrayList<>();
     // The of ordered component names as a result of a search query
@@ -268,7 +268,7 @@
      * Sets the current set of predicted apps.  Since this can be called before we get the full set
      * of applications, we should merge the results only in onAppsUpdated() which is idempotent.
      */
-    public void setPredictedApps(List<ComponentName> apps) {
+    public void setPredictedApps(List<ComponentKey> apps) {
         mPredictedAppComponents.clear();
         mPredictedAppComponents.addAll(apps);
         onAppsUpdated();
@@ -386,21 +386,27 @@
 
         if (DEBUG_PREDICTIONS) {
             if (mPredictedAppComponents.isEmpty() && !mApps.isEmpty()) {
-                mPredictedAppComponents.add(mApps.get(0).componentName);
-                mPredictedAppComponents.add(mApps.get(0).componentName);
-                mPredictedAppComponents.add(mApps.get(0).componentName);
-                mPredictedAppComponents.add(mApps.get(0).componentName);
+                mPredictedAppComponents.add(new ComponentKey(mApps.get(0).componentName,
+                        UserHandleCompat.myUserHandle()));
+                mPredictedAppComponents.add(new ComponentKey(mApps.get(0).componentName,
+                        UserHandleCompat.myUserHandle()));
+                mPredictedAppComponents.add(new ComponentKey(mApps.get(0).componentName,
+                        UserHandleCompat.myUserHandle()));
+                mPredictedAppComponents.add(new ComponentKey(mApps.get(0).componentName,
+                        UserHandleCompat.myUserHandle()));
             }
         }
 
         // Process the predicted app components
         mPredictedApps.clear();
         if (mPredictedAppComponents != null && !mPredictedAppComponents.isEmpty() && !hasFilter()) {
-            for (ComponentName cn : mPredictedAppComponents) {
-                for (AppInfo info : mApps) {
-                    if (cn.equals(info.componentName)) {
-                        mPredictedApps.add(info);
-                        break;
+            for (ComponentKey ck : mPredictedAppComponents) {
+                AppInfo info = mComponentToAppMap.get(ck);
+                if (info != null) {
+                    mPredictedApps.add(info);
+                } else {
+                    if (LauncherAppState.isDogfoodBuild()) {
+                        Log.e(TAG, "Predicted app not found: " + ck.flattenToString(mLauncher));
                     }
                 }
                 // Stop at the number of predicted apps
diff --git a/src/com/android/launcher3/util/ComponentKey.java b/src/com/android/launcher3/util/ComponentKey.java
index 0f17f00..6a7df43 100644
--- a/src/com/android/launcher3/util/ComponentKey.java
+++ b/src/com/android/launcher3/util/ComponentKey.java
@@ -17,8 +17,9 @@
  */
 
 import android.content.ComponentName;
-
+import android.content.Context;
 import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.compat.UserManagerCompat;
 
 import java.util.Arrays;
 
@@ -38,6 +39,35 @@
 
     }
 
+    /**
+     * Creates a new component key from an encoded component key string in the form of
+     * [flattenedComponentString#userId].  If the userId is not present, then it defaults
+     * to the current user.
+     */
+    public ComponentKey(Context context, String componentKeyStr) {
+        int userDelimiterIndex = componentKeyStr.indexOf("#");
+        if (userDelimiterIndex != -1) {
+            String componentStr = componentKeyStr.substring(0, userDelimiterIndex);
+            Long componentUser = Long.valueOf(componentKeyStr.substring(userDelimiterIndex + 1));
+            componentName = ComponentName.unflattenFromString(componentStr);
+            user = UserManagerCompat.getInstance(context)
+                    .getUserForSerialNumber(componentUser.longValue());
+        } else {
+            // No user provided, default to the current user
+            componentName = ComponentName.unflattenFromString(componentKeyStr);
+            user = UserHandleCompat.myUserHandle();
+        }
+        mHashCode = Arrays.hashCode(new Object[] {componentName, user});
+    }
+
+    /**
+     * Encodes a component key as a string of the form [flattenedComponentString#userId].
+     */
+    public String flattenToString(Context context) {
+        return componentName.flattenToString() + "#" +
+                UserManagerCompat.getInstance(context).getSerialNumberForUser(user);
+    }
+
     @Override
     public int hashCode() {
         return mHashCode;