Implement setActivityLabelAndIcon().

Replaces Activity.setRecentsLabel and Activity.setRecentsIcon.
Simple top-down traversal to find the highest activity with a
specified label and icon. Adds the Intent of that activity to
RecentTaskInfo as well so that Recents can get the launcher
icon if UX desires it.

Fixes bug 13675322.

Change-Id: I62d7d8f4df4dc81012f451e0cdea8a2943aedeec
diff --git a/api/current.txt b/api/current.txt
index 2ba5e5c..d0a955f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3142,6 +3142,7 @@
     method public void reportFullyDrawn();
     method public final boolean requestWindowFeature(int);
     method public final void runOnUiThread(java.lang.Runnable);
+    method public void setActivityLabelAndIcon(java.lang.CharSequence, android.graphics.Bitmap);
     method public void setContentTransitionManager(android.transition.TransitionManager);
     method public void setContentView(int);
     method public void setContentView(android.view.View);
@@ -3158,8 +3159,6 @@
     method public final void setProgressBarIndeterminate(boolean);
     method public final void setProgressBarIndeterminateVisibility(boolean);
     method public final void setProgressBarVisibility(boolean);
-    method public void setRecentsIcon(android.graphics.Bitmap);
-    method public void setRecentsLabel(java.lang.CharSequence);
     method public void setRequestedOrientation(int);
     method public final void setResult(int);
     method public final void setResult(int, android.content.Intent);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index e38bbb3..23caccc 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4701,42 +4701,33 @@
     }
 
     /**
-     * Set a label to be used in the Recents task display. The activities of a task are traversed
-     * in order from the topmost activity to the bottommost. As soon as one activity returns a
-     * non-null Recents label the traversal is ended and that value will be used in
-     * {@link ActivityManager.RecentTaskInfo#activityLabel}
+     * 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}. The {link Intent} for the activity that set
+     * activityLabel and activityIcon will be returned in {@link
+     * ActivityManager.RecentTaskInfo#activityIntent}
      *
      * @see ActivityManager#getRecentTasks
+     * @see ActivityManager.RecentTaskInfo
      *
-     * @param recentsLabel The label to use in the RecentTaskInfo.
+     * @param activityLabel The label to use in the RecentTaskInfo.
+     * @param activityIcon The Bitmap to use in the RecentTaskInfo.
      */
-    public void setRecentsLabel(CharSequence recentsLabel) {
-        try {
-            ActivityManagerNative.getDefault().setRecentsLabel(mToken, recentsLabel);
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Set an icon to be used in the Recents task display. The activities of a task are traversed
-     * in order from the topmost activity to the bottommost. As soon as one activity returns a
-     * non-null Recents icon the traversal is ended and that value will be used in
-     * {@link ActivityManager.RecentTaskInfo#activityIcon}.
-     *
-     * @see ActivityManager#getRecentTasks
-     *
-     * @param recentsIcon The Bitmap to use in the RecentTaskInfo.
-     */
-    public void setRecentsIcon(Bitmap recentsIcon) {
+    public void setActivityLabelAndIcon(CharSequence activityLabel, Bitmap activityIcon) {
         final Bitmap scaledIcon;
-        if (recentsIcon != null) {
+        if (activityIcon != null) {
             final int size = ActivityManager.getLauncherLargeIconSizeInner(this);
-            scaledIcon = Bitmap.createScaledBitmap(recentsIcon, size, size, true);
+            scaledIcon = Bitmap.createScaledBitmap(activityIcon, size, size, true);
         } else {
             scaledIcon = null;
         }
         try {
-            ActivityManagerNative.getDefault().setRecentsIcon(mToken, scaledIcon);
+            ActivityManagerNative.getDefault().setActivityLabelAndIcon(mToken, activityLabel,
+                    scaledIcon);
         } catch (RemoteException e) {
         }
     }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d386eff..5a08db7 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -516,14 +516,14 @@
         public int userId;
 
         /**
-         * The label of the highest activity in the task stack to have set a label
-         * {@link Activity#setRecentsLabel}.
+         * The label of the highest activity in the task stack to have set a label using
+         * {@link Activity#setActivityLabelAndIcon(CharSequence, android.graphics.Bitmap)}.
          */
         public CharSequence activityLabel;
 
         /**
          * The Bitmap icon of the highest activity in the task stack to set a Bitmap using
-         * {@link Activity#setRecentsIcon}.
+         * {@link Activity#setActivityLabelAndIcon(CharSequence, android.graphics.Bitmap)}.
          */
         public Bitmap activityIcon;
 
@@ -563,11 +563,7 @@
         public void readFromParcel(Parcel source) {
             id = source.readInt();
             persistentId = source.readInt();
-            if (source.readInt() != 0) {
-                baseIntent = Intent.CREATOR.createFromParcel(source);
-            } else {
-                baseIntent = null;
-            }
+            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);
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 707a038..a37a35a 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2129,21 +2129,13 @@
             return true;
         }
 
-        case SET_RECENTS_LABEL_TRANSACTION: {
+        case SET_ACTIVITY_LABEL_ICON_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
-            CharSequence recentsLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(data);
-            setRecentsLabel(token, recentsLabel);
-            reply.writeNoException();
-            return true;
-        }
-
-        case SET_RECENTS_ICON_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            Bitmap recentsIcon = data.readInt() != 0
+            CharSequence activityLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(data);
+            Bitmap activityIcon = data.readInt() > 0
                     ? Bitmap.CREATOR.createFromParcel(data) : null;
-            setRecentsIcon(token, recentsIcon);
+            setActivityLabelAndIcon(token, activityLabel, activityIcon);
             reply.writeNoException();
             return true;
         }
@@ -4918,32 +4910,22 @@
         return isInLockTaskMode;
     }
 
-    public void setRecentsLabel(IBinder token, CharSequence recentsLabel) throws RemoteException
+    @Override
+    public void setActivityLabelAndIcon(IBinder token, CharSequence activityLabel,
+            Bitmap activityIcon) throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(token);
-        TextUtils.writeToParcel(recentsLabel, data, 0);
-        mRemote.transact(SET_RECENTS_LABEL_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void setRecentsIcon(IBinder token, Bitmap recentsBitmap) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        if (recentsBitmap != null) {
+        TextUtils.writeToParcel(activityLabel, data, 0);
+        if (activityIcon != null) {
             data.writeInt(1);
-            recentsBitmap.writeToParcel(data, 0);
+            activityIcon.writeToParcel(data, 0);
         } else {
             data.writeInt(0);
         }
-        mRemote.transact(SET_RECENTS_ICON_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+        mRemote.transact(SET_ACTIVITY_LABEL_ICON_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 3b56839..f7416d6 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -437,10 +437,8 @@
     public boolean isInLockTaskMode() throws RemoteException;
 
     /** @hide */
-    public void setRecentsLabel(IBinder token, CharSequence recentsLabel) throws RemoteException;
-
-    /** @hide */
-    public void setRecentsIcon(IBinder token, Bitmap recentsBitmap) throws RemoteException;
+    public void setActivityLabelAndIcon(IBinder token, CharSequence activityLabel,
+            Bitmap activityBitmap) throws RemoteException;
 
     /*
      * Private non-Binder interfaces
@@ -741,6 +739,5 @@
     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_RECENTS_LABEL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+217;
-    int SET_RECENTS_ICON_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+218;
+    int SET_ACTIVITY_LABEL_ICON_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+217;
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5fa9084..b6fc7c3 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -6895,18 +6895,27 @@
                     rti.stackId = tr.stack.mStackId;
                     rti.userId = tr.userId;
 
+                    // Traverse upwards looking for any break between main task activities and
+                    // utility activities.
                     final ArrayList<ActivityRecord> activities = tr.mActivities;
-                    int numSet = 0;
-                    for (int activityNdx = activities.size() - 1; activityNdx >= 0 && numSet < 2;
-                            --activityNdx) {
+                    int activityNdx;
+                    final int numActivities = activities.size();
+                    for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
+                            ++activityNdx) {
                         final ActivityRecord r = activities.get(activityNdx);
-                        if (rti.activityLabel == null && r.recentsLabel != null) {
-                            rti.activityLabel = r.recentsLabel;
-                            ++numSet;
+                        if (r.intent != null &&
+                                (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
+                                        != 0) {
+                            break;
                         }
-                        if (rti.activityIcon == null && r.recentsIcon != null) {
-                            rti.activityIcon = r.recentsIcon;
-                            ++numSet;
+                    }
+                    // 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;
                         }
                     }
 
@@ -6975,21 +6984,13 @@
     }
 
     @Override
-    public void setRecentsLabel(IBinder token, CharSequence recentsLabel) {
+    public void setActivityLabelAndIcon(IBinder token, CharSequence activityLabel,
+            Bitmap activityIcon) {
         synchronized (this) {
             ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r != null) {
-                r.recentsLabel = recentsLabel.toString();
-            }
-        }
-    }
-
-    @Override
-    public void setRecentsIcon(IBinder token, Bitmap recentsIcon) {
-        synchronized (this) {
-            ActivityRecord r = ActivityRecord.isInStackLocked(token);
-            if (r != null) {
-                r.recentsIcon = recentsIcon;
+                r.activityLabel = activityLabel.toString();
+                r.activityIcon = activityIcon;
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 77f5c59..33b12c5 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -148,8 +148,8 @@
     boolean mStartingWindowShown = false;
     ActivityContainer mInitialActivityContainer;
 
-    String recentsLabel;
-    Bitmap recentsIcon;
+    String activityLabel;
+    Bitmap activityIcon;
 
     void dump(PrintWriter pw, String prefix) {
         final long now = SystemClock.uptimeMillis();