Start using the new activity options argument.

New class lets you make an options bundle defining a custom animation,
as an alternative to Activity.overridePendingTransition().

Change-Id: I8e209bf52398a98ab9f1bcafa1ec0a580dae57c0
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index caee1ab..d21212f 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -2258,7 +2258,7 @@
         for (int i=0; i<N; i++) {
             PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
             mMainStack.startActivityUncheckedLocked(pal.r, pal.sourceRecord,
-                    pal.startFlags, doResume && i == (N-1));
+                    pal.startFlags, doResume && i == (N-1), null);
         }
         mPendingActivityLaunches.clear();
     }
@@ -4252,7 +4252,8 @@
 
     public IIntentSender getIntentSender(int type,
             String packageName, IBinder token, String resultWho,
-            int requestCode, Intent[] intents, String[] resolvedTypes, int flags) {
+            int requestCode, Intent[] intents, String[] resolvedTypes,
+            int flags, Bundle options) {
         enforceNotIsolatedCaller("getIntentSender");
         // Refuse possible leaked file descriptors
         if (intents != null) {
@@ -4278,6 +4279,11 @@
                         "Intent array length does not match resolvedTypes length");
             }
         }
+        if (options != null) {
+            if (options.hasFileDescriptors()) {
+                throw new IllegalArgumentException("File descriptors passed in options");
+            }
+        }
         
         synchronized(this) {
             int callingUid = Binder.getCallingUid();
@@ -4300,7 +4306,7 @@
                     Slog.i(TAG_MU, "Getting intent sender for origCallingUid="
                             + Binder.getOrigCallingUid());
                 return getIntentSenderLocked(type, packageName, Binder.getOrigCallingUid(),
-                        token, resultWho, requestCode, intents, resolvedTypes, flags);
+                        token, resultWho, requestCode, intents, resolvedTypes, flags, options);
                 
             } catch (RemoteException e) {
                 throw new SecurityException(e);
@@ -4310,7 +4316,8 @@
     
     IIntentSender getIntentSenderLocked(int type,
             String packageName, int callingUid, IBinder token, String resultWho,
-            int requestCode, Intent[] intents, String[] resolvedTypes, int flags) {
+            int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
+            Bundle options) {
         if (DEBUG_MU)
             Slog.v(TAG_MU, "getIntentSenderLocked(): uid=" + callingUid);
         ActivityRecord activity = null;
@@ -4332,7 +4339,7 @@
 
         PendingIntentRecord.Key key = new PendingIntentRecord.Key(
                 type, packageName, activity, resultWho,
-                requestCode, intents, resolvedTypes, flags);
+                requestCode, intents, resolvedTypes, flags, options);
         WeakReference<PendingIntentRecord> ref;
         ref = mIntentSenderRecords.get(key);
         PendingIntentRecord rec = ref != null ? ref.get() : null;
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index b42d98ea..53cb2b0 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -20,6 +20,7 @@
 import com.android.server.am.ActivityStack.ActivityState;
 
 import android.app.Activity;
+import android.app.ActivityOptions;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -95,6 +96,7 @@
     ArrayList results;      // pending ActivityResult objs we have received
     HashSet<WeakReference<PendingIntentRecord>> pendingResults; // all pending intents for this act
     ArrayList newIntents;   // any pending new intents for single-top mode
+    ActivityOptions pendingOptions; // most recently given options
     HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold
     UriPermissionOwner uriPermissions; // current special URI access perms.
     ProcessRecord app;      // if non-null, hosting application
@@ -538,6 +540,28 @@
         }
     }
 
+    void updateOptionsLocked(Bundle options) {
+        if (options != null) {
+            pendingOptions = new ActivityOptions(options);
+        }
+    }
+
+    void applyOptionsLocked() {
+        if (pendingOptions != null) {
+            if (pendingOptions.isCustomAnimation()) {
+                service.mWindowManager.overridePendingAppTransition(
+                        pendingOptions.getPackageName(),
+                        pendingOptions.getCustomEnterResId(),
+                        pendingOptions.getCustomExitResId());
+            }
+            pendingOptions = null;
+        }
+    }
+
+    void clearOptionsLocked() {
+        pendingOptions = null;
+    }
+
     void removeUriPermissionsLocked() {
         if (uriPermissions != null) {
             uriPermissions.removeUriPermissionsLocked();
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 13ee008..7e8df35 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -22,6 +22,7 @@
 
 import android.app.Activity;
 import android.app.ActivityManager;
+import android.app.ActivityOptions;
 import android.app.AppGlobals;
 import android.app.IActivityManager;
 import android.app.IThumbnailRetriever;
@@ -1456,6 +1457,7 @@
         // We are starting up the next activity, so tell the window manager
         // that the previous one will be hidden soon.  This way it can know
         // to ignore it when computing the desired screen orientation.
+        boolean noAnim = false;
         if (prev != null) {
             if (prev.finishing) {
                 if (DEBUG_TRANSITION) Slog.v(TAG,
@@ -1474,6 +1476,7 @@
                 if (DEBUG_TRANSITION) Slog.v(TAG,
                         "Prepare open transition: prev=" + prev);
                 if (mNoAnimActivities.contains(next)) {
+                    noAnim = true;
                     mService.mWindowManager.prepareAppTransition(
                             WindowManagerPolicy.TRANSIT_NONE, false);
                 } else {
@@ -1490,6 +1493,7 @@
             if (DEBUG_TRANSITION) Slog.v(TAG,
                     "Prepare open transition: no previous");
             if (mNoAnimActivities.contains(next)) {
+                noAnim = true;
                 mService.mWindowManager.prepareAppTransition(
                         WindowManagerPolicy.TRANSIT_NONE, false);
             } else {
@@ -1497,6 +1501,11 @@
                         WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN, false);
             }
         }
+        if (!noAnim) {
+            next.applyOptionsLocked();
+        } else {
+            next.clearOptionsLocked();
+        }
 
         if (next.app != null && next.app.thread != null) {
             if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next);
@@ -1655,7 +1664,7 @@
     }
 
     private final void startActivityLocked(ActivityRecord r, boolean newTask,
-            boolean doResume, boolean keepCurTransition) {
+            boolean doResume, boolean keepCurTransition, Bundle options) {
         final int NH = mHistory.size();
 
         int addPos = -1;
@@ -1748,6 +1757,7 @@
                         : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN, keepCurTransition);
                 mNoAnimActivities.remove(r);
             }
+            r.updateOptionsLocked(options);
             mService.mWindowManager.addAppToken(
                     addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen);
             boolean doShow = true;
@@ -2457,7 +2467,7 @@
         }
         
         err = startActivityUncheckedLocked(r, sourceRecord,
-                startFlags, true);
+                startFlags, true, options);
         if (mDismissKeyguardOnNextActivity && mPausingActivity == null) {
             // Someone asked to have the keyguard dismissed on the next
             // activity start, but we are not actually doing an activity
@@ -2480,7 +2490,8 @@
     }
 
     final int startActivityUncheckedLocked(ActivityRecord r,
-            ActivityRecord sourceRecord, int startFlags, boolean doResume) {
+            ActivityRecord sourceRecord, int startFlags, boolean doResume,
+            Bundle options) {
         final Intent intent = r.intent;
         final int callingUid = r.launchedFromUid;
         final int userId = r.userId;
@@ -2591,6 +2602,7 @@
                             // We really do want to push this one into the
                             // user's face, right now.
                             moveHomeToFrontFromLaunchLocked(launchFlags);
+                            r.updateOptionsLocked(options);
                             moveTaskToFrontLocked(taskTop.task, r);
                         }
                     }
@@ -2794,6 +2806,7 @@
                 if (where >= 0) {
                     ActivityRecord top = moveActivityToFrontLocked(where);
                     logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
+                    top.updateOptionsLocked(options);
                     top.deliverNewIntentLocked(callingUid, r.intent);
                     if (doResume) {
                         resumeTopActivityLocked(null);
@@ -2829,7 +2842,7 @@
             EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
         }
         logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
-        startActivityLocked(r, newTask, doResume, keepCurTransition);
+        startActivityLocked(r, newTask, doResume, keepCurTransition, options);
         return ActivityManager.START_SUCCESS;
     }
 
@@ -2944,7 +2957,7 @@
                                 ActivityManager.INTENT_SENDER_ACTIVITY, "android",
                                 realCallingUid, null, null, 0, new Intent[] { intent },
                                 new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT
-                                | PendingIntent.FLAG_ONE_SHOT);
+                                | PendingIntent.FLAG_ONE_SHOT, null);
                         
                         Intent newIntent = new Intent();
                         if (requestCode >= 0) {
@@ -3095,9 +3108,15 @@
                                 "FLAG_CANT_SAVE_STATE not supported here");
                     }
 
+                    Bundle theseOptions;
+                    if (options != null && i == intents.length-1) {
+                        theseOptions = options;
+                    } else {
+                        theseOptions = null;
+                    }
                     int res = startActivityLocked(caller, intent, resolvedTypes[i],
                             aInfo, resultTo, null, -1, callingPid, callingUid,
-                            0, options, componentSpecified, outActivity);
+                            0, theseOptions, componentSpecified, outActivity);
                     if (res < 0) {
                         return res;
                     }
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java
index 9676084..ad15da1 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/java/com/android/server/am/PendingIntentRecord.java
@@ -49,6 +49,7 @@
         final int requestCode;
         final Intent requestIntent;
         final String requestResolvedType;
+        final Bundle options;
         Intent[] allIntents;
         String[] allResolvedTypes;
         final int flags;
@@ -57,7 +58,7 @@
         private static final int ODD_PRIME_NUMBER = 37;
         
         Key(int _t, String _p, ActivityRecord _a, String _w,
-                int _r, Intent[] _i, String[] _it, int _f) {
+                int _r, Intent[] _i, String[] _it, int _f, Bundle _o) {
             type = _t;
             packageName = _p;
             activity = _a;
@@ -68,6 +69,7 @@
             allIntents = _i;
             allResolvedTypes = _it;
             flags = _f;
+            options = _o;
             
             int hash = 23;
             hash = (ODD_PRIME_NUMBER*hash) + _f;
@@ -215,6 +217,13 @@
                 boolean sendFinish = finishedReceiver != null;
                 switch (key.type) {
                     case ActivityManager.INTENT_SENDER_ACTIVITY:
+                        if (options == null) {
+                            options = key.options;
+                        } else if (key.options != null) {
+                            Bundle opts = new Bundle(key.options);
+                            opts.putAll(options);
+                            options = opts;
+                        }
                         try {
                             if (key.allIntents != null && key.allIntents.length > 1) {
                                 Intent[] allIntents = new Intent[key.allIntents.length];