Refactoring activity method to update recents values.

Change-Id: Ic525be207714d34abe0c2d26091c3e46abcd9bad
diff --git a/api/current.txt b/api/current.txt
index 06d1ab0..c64156f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3316,7 +3316,6 @@
     method public final boolean requestWindowFeature(int);
     method public final void runOnUiThread(java.lang.Runnable);
     method public void setActionBar(android.widget.Toolbar);
-    method public void setActivityLabelAndIcon(java.lang.CharSequence, android.graphics.Bitmap);
     method public void setActivityTransitionListener(android.app.ActivityOptions.ActivityTransitionListener);
     method public void setContentTransitionManager(android.transition.TransitionManager);
     method public void setContentView(int);
@@ -3334,6 +3333,7 @@
     method public final void setProgressBarIndeterminate(boolean);
     method public final void setProgressBarIndeterminateVisibility(boolean);
     method public final void setProgressBarVisibility(boolean);
+    method public void setRecentsActivityValues(android.app.ActivityManager.RecentsActivityValues);
     method public void setRequestedOrientation(int);
     method public final void setResult(int);
     method public final void setResult(int, android.content.Intent);
@@ -3454,8 +3454,7 @@
     method public void readFromParcel(android.os.Parcel);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
-    field public android.graphics.Bitmap activityIcon;
-    field public java.lang.CharSequence activityLabel;
+    field public android.app.ActivityManager.RecentsActivityValues activityValues;
     field public android.content.Intent baseIntent;
     field public java.lang.CharSequence description;
     field public int id;
@@ -3463,6 +3462,21 @@
     field public int persistentId;
   }
 
+  public static class ActivityManager.RecentsActivityValues implements android.os.Parcelable {
+    ctor public ActivityManager.RecentsActivityValues(android.app.ActivityManager.RecentsActivityValues);
+    ctor public ActivityManager.RecentsActivityValues(java.lang.CharSequence, android.graphics.Bitmap, int);
+    ctor public ActivityManager.RecentsActivityValues(java.lang.CharSequence, android.graphics.Bitmap);
+    ctor public ActivityManager.RecentsActivityValues(java.lang.CharSequence);
+    ctor public ActivityManager.RecentsActivityValues();
+    method public int describeContents();
+    method public void readFromParcel(android.os.Parcel);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public int colorPrimary;
+    field public android.graphics.Bitmap icon;
+    field public java.lang.CharSequence label;
+  }
+
   public static class ActivityManager.RunningAppProcessInfo implements android.os.Parcelable {
     ctor public ActivityManager.RunningAppProcessInfo();
     ctor public ActivityManager.RunningAppProcessInfo(java.lang.String, int, java.lang.String[]);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 8981c88..5ec3117 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3493,6 +3493,16 @@
             }
             theme.applyStyle(resid, false);
         }
+
+        // Get the primary color and update the RecentsActivityValues for this activity
+        TypedArray a = getTheme().obtainStyledAttributes(com.android.internal.R.styleable.Theme);
+        int colorPrimary = a.getColor(com.android.internal.R.styleable.Theme_colorPrimary, 0);
+        a.recycle();
+        if (colorPrimary != 0) {
+            ActivityManager.RecentsActivityValues v = new ActivityManager.RecentsActivityValues();
+            v.colorPrimary = colorPrimary;
+            setRecentsActivityValues(v);
+        }
     }
 
     /**
@@ -4779,31 +4789,26 @@
     }
 
     /**
-     * Set a label and icon to be used in the Recents task display. When {@link
-     * ActivityManager#getRecentTasks} is called, the activities of each task are
-     * traversed in order from the topmost activity to the bottommost. As soon as one activity is
-     * found with either a non-null label or a non-null icon set by this call the traversal is
-     * ended. For each task those values will be returned in {@link
-     * ActivityManager.RecentTaskInfo#activityLabel} and {@link
-     * ActivityManager.RecentTaskInfo#activityIcon}.
+     * Sets information describing this Activity for presentation inside the Recents System UI. When
+     * {@link ActivityManager#getRecentTasks} is called, the activities of each task are
+     * traversed in order from the topmost activity to the bottommost. The traversal continues for
+     * each property until a suitable value is found. For each task those values will be returned in
+     * {@link android.app.ActivityManager.RecentsActivityValues}.
      *
      * @see ActivityManager#getRecentTasks
-     * @see ActivityManager.RecentTaskInfo
+     * @see android.app.ActivityManager.RecentsActivityValues
      *
-     * @param activityLabel The label to use in the RecentTaskInfo.
-     * @param activityIcon The Bitmap to use in the RecentTaskInfo.
+     * @param values The Recents values that describe this activity.
      */
-    public void setActivityLabelAndIcon(CharSequence activityLabel, Bitmap activityIcon) {
-        final Bitmap scaledIcon;
-        if (activityIcon != null) {
+    public void setRecentsActivityValues(ActivityManager.RecentsActivityValues values) {
+        ActivityManager.RecentsActivityValues activityValues =
+                new ActivityManager.RecentsActivityValues(values);
+        if (values.icon != null) {
             final int size = ActivityManager.getLauncherLargeIconSizeInner(this);
-            scaledIcon = Bitmap.createScaledBitmap(activityIcon, size, size, true);
-        } else {
-            scaledIcon = null;
+            activityValues.icon = Bitmap.createScaledBitmap(values.icon, size, size, true);
         }
         try {
-            ActivityManagerNative.getDefault().setActivityLabelAndIcon(mToken, activityLabel,
-                    scaledIcon);
+            ActivityManagerNative.getDefault().setRecentsActivityValues(mToken, activityValues);
         } catch (RemoteException e) {
         }
     }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 5f4ca4e..5d809d8 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -475,6 +475,111 @@
     }
 
     /**
+     * Information you can set and retrieve about the current activity within Recents.
+     */
+    public static class RecentsActivityValues implements Parcelable {
+        public CharSequence label;
+        public Bitmap icon;
+        public int colorPrimary;
+
+        public RecentsActivityValues(RecentsActivityValues values) {
+            copyFrom(values);
+        }
+
+        /**
+         * Creates the RecentsActivityValues to the specified values.
+         *
+         * @param label A label and description of the current state of this activity.
+         * @param icon An icon that represents the current state of this activity.
+         * @param color A color to override the theme's primary color.
+         */
+        public RecentsActivityValues(CharSequence label, Bitmap icon, int color) {
+            this.label = label;
+            this.icon = icon;
+            this.colorPrimary = color;
+        }
+
+        /**
+         * Creates the RecentsActivityValues to the specified values.
+         *
+         * @param label A label and description of the current state of this activity.
+         * @param icon An icon that represents the current state of this activity.
+         */
+        public RecentsActivityValues(CharSequence label, Bitmap icon) {
+            this(label, icon, 0);
+        }
+
+        /**
+         * Creates the RecentsActivityValues to the specified values.
+         *
+         * @param label A label and description of the current state of this activity.
+         */
+        public RecentsActivityValues(CharSequence label) {
+            this(label, null, 0);
+        }
+
+        public RecentsActivityValues() {
+            this(null, null, 0);
+        }
+
+        private RecentsActivityValues(Parcel source) {
+            readFromParcel(source);
+        }
+
+        /**
+         * Do a shallow copy of another set of activity values.
+         * @hide
+         */
+        public void copyFrom(RecentsActivityValues v) {
+            if (v != null) {
+                label = v.label;
+                icon = v.icon;
+                colorPrimary = v.colorPrimary;
+            }
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            TextUtils.writeToParcel(label, dest,
+                    Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+            if (icon == null) {
+                dest.writeInt(0);
+            } else {
+                dest.writeInt(1);
+                icon.writeToParcel(dest, 0);
+            }
+            dest.writeInt(colorPrimary);
+        }
+
+        public void readFromParcel(Parcel source) {
+            label = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
+            icon = source.readInt() > 0 ? Bitmap.CREATOR.createFromParcel(source) : null;
+            colorPrimary = source.readInt();
+        }
+
+        public static final Creator<RecentsActivityValues> CREATOR
+                = new Creator<RecentsActivityValues>() {
+            public RecentsActivityValues createFromParcel(Parcel source) {
+                return new RecentsActivityValues(source);
+            }
+            public RecentsActivityValues[] newArray(int size) {
+                return new RecentsActivityValues[size];
+            }
+        };
+
+        @Override
+        public String toString() {
+            return "RecentsActivityValues Label: " + label + " Icon: " + icon +
+                    " colorPrimary: " + colorPrimary;
+        }
+    }
+
+    /**
      * Information you can retrieve about tasks that the user has most recently
      * started or visited.
      */
@@ -523,16 +628,10 @@
         public int userId;
 
         /**
-         * The label of the highest activity in the task stack to have set a label using
-         * {@link Activity#setActivityLabelAndIcon(CharSequence, android.graphics.Bitmap)}.
+         * The recent activity values for the highest activity in the stack to have set the values.
+         * {@link Activity#setRecentsActivityValues(android.app.ActivityManager.RecentsActivityValues)}.
          */
-        public CharSequence activityLabel;
-
-        /**
-         * The Bitmap icon of the highest activity in the task stack to set a Bitmap using
-         * {@link Activity#setActivityLabelAndIcon(CharSequence, android.graphics.Bitmap)}.
-         */
-        public Bitmap activityIcon;
+        public RecentsActivityValues activityValues;
 
         public RecentTaskInfo() {
         }
@@ -555,13 +654,11 @@
             ComponentName.writeToParcel(origActivity, dest);
             TextUtils.writeToParcel(description, dest,
                     Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-            TextUtils.writeToParcel(activityLabel, dest,
-                    Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-            if (activityIcon == null) {
-                dest.writeInt(0);
-            } else {
+            if (activityValues != null) {
                 dest.writeInt(1);
-                activityIcon.writeToParcel(dest, 0);
+                activityValues.writeToParcel(dest, 0);
+            } else {
+                dest.writeInt(0);
             }
             dest.writeInt(stackId);
             dest.writeInt(userId);
@@ -573,8 +670,8 @@
             baseIntent = source.readInt() > 0 ? Intent.CREATOR.createFromParcel(source) : null;
             origActivity = ComponentName.readFromParcel(source);
             description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
-            activityLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
-            activityIcon = source.readInt() > 0 ? Bitmap.CREATOR.createFromParcel(source) : null;
+            activityValues = source.readInt() > 0 ?
+                    RecentsActivityValues.CREATOR.createFromParcel(source) : null;
             stackId = source.readInt();
             userId = source.readInt();
         }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 6a818ac..57da21e 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2119,13 +2119,12 @@
             return true;
         }
 
-        case SET_ACTIVITY_LABEL_ICON_TRANSACTION: {
+        case SET_RECENTS_ACTIVITY_VALUES_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
-            CharSequence activityLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(data);
-            Bitmap activityIcon = data.readInt() > 0
-                    ? Bitmap.CREATOR.createFromParcel(data) : null;
-            setActivityLabelAndIcon(token, activityLabel, activityIcon);
+            ActivityManager.RecentsActivityValues values =
+                    ActivityManager.RecentsActivityValues.CREATOR.createFromParcel(data);
+            setRecentsActivityValues(token, values);
             reply.writeNoException();
             return true;
         }
@@ -4883,21 +4882,14 @@
     }
 
     @Override
-    public void setActivityLabelAndIcon(IBinder token, CharSequence activityLabel,
-            Bitmap activityIcon) throws RemoteException
-    {
+    public void setRecentsActivityValues(IBinder token, ActivityManager.RecentsActivityValues values)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(token);
-        TextUtils.writeToParcel(activityLabel, data, 0);
-        if (activityIcon != null) {
-            data.writeInt(1);
-            activityIcon.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        mRemote.transact(SET_ACTIVITY_LABEL_ICON_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+        values.writeToParcel(data, 0);
+        mRemote.transact(SET_RECENTS_ACTIVITY_VALUES_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
         reply.readException();
         data.recycle();
         reply.recycle();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 5ca51be..2e9cdf3b7 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -435,8 +435,8 @@
     public boolean isInLockTaskMode() throws RemoteException;
 
     /** @hide */
-    public void setActivityLabelAndIcon(IBinder token, CharSequence activityLabel,
-            Bitmap activityBitmap) throws RemoteException;
+    public void setRecentsActivityValues(IBinder token, ActivityManager.RecentsActivityValues values)
+            throws RemoteException;
 
     /*
      * Private non-Binder interfaces
@@ -734,6 +734,6 @@
     int START_LOCK_TASK_BY_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+214;
     int STOP_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+215;
     int IS_IN_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+216;
-    int SET_ACTIVITY_LABEL_ICON_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+217;
+    int SET_RECENTS_ACTIVITY_VALUES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+217;
     int START_VOICE_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+218;
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index bcc6359..f908de2 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -7070,8 +7070,7 @@
                     final ArrayList<ActivityRecord> activities = tr.mActivities;
                     int activityNdx;
                     final int numActivities = activities.size();
-                    for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
-                            ++activityNdx) {
+                    for (activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
                         final ActivityRecord r = activities.get(activityNdx);
                         if (r.intent != null &&
                                 (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
@@ -7079,14 +7078,34 @@
                             break;
                         }
                     }
-                    // Traverse downwards starting below break looking for set label and icon.
-                    for (--activityNdx; activityNdx >= 0; --activityNdx) {
-                        final ActivityRecord r = activities.get(activityNdx);
-                        if (r.activityLabel != null || r.activityIcon != null) {
-                            rti.activityLabel = r.activityLabel;
-                            rti.activityIcon = r.activityIcon;
-                            break;
+                    if (activityNdx > 0) {
+                        // Traverse downwards starting below break looking for set label, icon.
+                        // Note that if there are activities in the task but none of them set the
+                        // recent activity values, then we do not fall back to the last set
+                        // values in the TaskRecord.
+                        rti.activityValues = new ActivityManager.RecentsActivityValues();
+                        for (--activityNdx; activityNdx >= 0; --activityNdx) {
+                            final ActivityRecord r = activities.get(activityNdx);
+                            if (r.activityValues != null) {
+                                if (rti.activityValues.label == null) {
+                                    rti.activityValues.label = r.activityValues.label;
+                                    tr.lastActivityValues.label = r.activityValues.label;
+                                }
+                                if (rti.activityValues.icon == null) {
+                                    rti.activityValues.icon = r.activityValues.icon;
+                                    tr.lastActivityValues.icon = r.activityValues.icon;
+                                }
+                                if (rti.activityValues.colorPrimary == 0) {
+                                    rti.activityValues.colorPrimary = r.activityValues.colorPrimary;
+                                    tr.lastActivityValues.colorPrimary = r.activityValues.colorPrimary;
+                                }
+                            }
                         }
+                    } else {
+                        // If there are no activity records in this task, then we use the last
+                        // resolved values
+                        rti.activityValues =
+                                new ActivityManager.RecentsActivityValues(tr.lastActivityValues);
                     }
 
                     if ((flags&ActivityManager.RECENT_IGNORE_UNAVAILABLE) != 0) {
@@ -7154,13 +7173,11 @@
     }
 
     @Override
-    public void setActivityLabelAndIcon(IBinder token, CharSequence activityLabel,
-            Bitmap activityIcon) {
+    public void setRecentsActivityValues(IBinder token, ActivityManager.RecentsActivityValues rav) {
         synchronized (this) {
             ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r != null) {
-                r.activityLabel = activityLabel.toString();
-                r.activityIcon = activityIcon;
+                r.activityValues = rav;
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 7a08cdd..f506eab 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -23,6 +23,7 @@
 import com.android.server.am.ActivityStack.ActivityState;
 import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
 
+import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.ResultInfo;
 import android.content.ComponentName;
@@ -147,8 +148,7 @@
     boolean mStartingWindowShown = false;
     ActivityContainer mInitialActivityContainer;
 
-    String activityLabel;
-    Bitmap activityIcon;
+    ActivityManager.RecentsActivityValues activityValues; // the recents information for this activity
 
     void dump(PrintWriter pw, String prefix) {
         final long now = SystemClock.uptimeMillis();
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index f4dd15e..9f0bc10 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -56,6 +56,11 @@
 
     int numFullscreen;      // Number of fullscreen activities.
 
+    // This represents the last resolved activity values for this task
+    // NOTE: This value needs to be persisted with each task
+    ActivityManager.RecentsActivityValues lastActivityValues =
+            new ActivityManager.RecentsActivityValues();
+
     /** List of all activities in the task arranged in history order */
     final ArrayList<ActivityRecord> mActivities = new ArrayList<ActivityRecord>();