Merge "Add ability to filter remote animation adapter by activity type" into pi-dev
diff --git a/core/java/android/view/RemoteAnimationDefinition.java b/core/java/android/view/RemoteAnimationDefinition.java
index 8def435..d2240e1 100644
--- a/core/java/android/view/RemoteAnimationDefinition.java
+++ b/core/java/android/view/RemoteAnimationDefinition.java
@@ -16,10 +16,14 @@
 
 package android.view;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+
 import android.annotation.Nullable;
+import android.app.WindowConfiguration;
+import android.app.WindowConfiguration.ActivityType;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.SparseArray;
 import android.view.WindowManager.TransitionType;
 
@@ -30,7 +34,7 @@
  */
 public class RemoteAnimationDefinition implements Parcelable {
 
-    private final SparseArray<RemoteAnimationAdapter> mTransitionAnimationMap;
+    private final SparseArray<RemoteAnimationAdapterEntry> mTransitionAnimationMap;
 
     public RemoteAnimationDefinition() {
         mTransitionAnimationMap = new SparseArray<>();
@@ -40,34 +44,70 @@
      * Registers a remote animation for a specific transition.
      *
      * @param transition The transition type. Must be one of WindowManager.TRANSIT_* values.
+     * @param activityTypeFilter The remote animation only runs if an activity with type of this
+     *                           parameter is involved in the transition.
+     * @param adapter The adapter that described how to run the remote animation.
+     */
+    public void addRemoteAnimation(@TransitionType int transition,
+            @ActivityType int activityTypeFilter, RemoteAnimationAdapter adapter) {
+        mTransitionAnimationMap.put(transition,
+                new RemoteAnimationAdapterEntry(adapter, activityTypeFilter));
+    }
+
+    /**
+     * Registers a remote animation for a specific transition without defining an activity type
+     * filter.
+     *
+     * @param transition The transition type. Must be one of WindowManager.TRANSIT_* values.
      * @param adapter The adapter that described how to run the remote animation.
      */
     public void addRemoteAnimation(@TransitionType int transition, RemoteAnimationAdapter adapter) {
-        mTransitionAnimationMap.put(transition, adapter);
+        addRemoteAnimation(transition, ACTIVITY_TYPE_UNDEFINED, adapter);
     }
 
     /**
      * Checks whether a remote animation for specific transition is defined.
      *
      * @param transition The transition type. Must be one of WindowManager.TRANSIT_* values.
+     * @param activityTypes The set of activity types of activities that are involved in the
+     *                      transition. Will be used for filtering.
      * @return Whether this definition has defined a remote animation for the specified transition.
      */
-    public boolean hasTransition(@TransitionType int transition) {
-        return mTransitionAnimationMap.get(transition) != null;
+    public boolean hasTransition(@TransitionType int transition, ArraySet<Integer> activityTypes) {
+        return getAdapter(transition, activityTypes) != null;
     }
 
     /**
      * Retrieves the remote animation for a specific transition.
      *
      * @param transition The transition type. Must be one of WindowManager.TRANSIT_* values.
+     * @param activityTypes The set of activity types of activities that are involved in the
+     *                      transition. Will be used for filtering.
      * @return The remote animation adapter for the specified transition.
      */
-    public @Nullable RemoteAnimationAdapter getAdapter(@TransitionType int transition) {
-        return mTransitionAnimationMap.get(transition);
+    public @Nullable RemoteAnimationAdapter getAdapter(@TransitionType int transition,
+            ArraySet<Integer> activityTypes) {
+        final RemoteAnimationAdapterEntry entry = mTransitionAnimationMap.get(transition);
+        if (entry == null) {
+            return null;
+        }
+        if (entry.activityTypeFilter == ACTIVITY_TYPE_UNDEFINED
+                || activityTypes.contains(entry.activityTypeFilter)) {
+            return entry.adapter;
+        } else {
+            return null;
+        }
     }
 
     public RemoteAnimationDefinition(Parcel in) {
-        mTransitionAnimationMap = in.readSparseArray(null /* loader */);
+        final int size = in.readInt();
+        mTransitionAnimationMap = new SparseArray<>(size);
+        for (int i = 0; i < size; i++) {
+            final int transition = in.readInt();
+            final RemoteAnimationAdapterEntry entry = in.readTypedObject(
+                    RemoteAnimationAdapterEntry.CREATOR);
+            mTransitionAnimationMap.put(transition, entry);
+        }
     }
 
     /**
@@ -76,7 +116,7 @@
      */
     public void setCallingPid(int pid) {
         for (int i = mTransitionAnimationMap.size() - 1; i >= 0; i--) {
-            mTransitionAnimationMap.valueAt(i).setCallingPid(pid);
+            mTransitionAnimationMap.valueAt(i).adapter.setCallingPid(pid);
         }
     }
 
@@ -87,7 +127,12 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeSparseArray((SparseArray) mTransitionAnimationMap);
+        final int size = mTransitionAnimationMap.size();
+        dest.writeInt(size);
+        for (int i = 0; i < size; i++) {
+            dest.writeInt(mTransitionAnimationMap.keyAt(i));
+            dest.writeTypedObject(mTransitionAnimationMap.valueAt(i), flags);
+        }
     }
 
     public static final Creator<RemoteAnimationDefinition> CREATOR =
@@ -100,4 +145,50 @@
             return new RemoteAnimationDefinition[size];
         }
     };
+
+    private static class RemoteAnimationAdapterEntry implements Parcelable {
+
+        final RemoteAnimationAdapter adapter;
+
+        /**
+         * Only run the transition if one of the activities matches the filter.
+         * {@link WindowConfiguration.ACTIVITY_TYPE_UNDEFINED} means no filter
+         */
+        @ActivityType final int activityTypeFilter;
+
+        RemoteAnimationAdapterEntry(RemoteAnimationAdapter adapter, int activityTypeFilter) {
+            this.adapter = adapter;
+            this.activityTypeFilter = activityTypeFilter;
+        }
+
+        private RemoteAnimationAdapterEntry(Parcel in) {
+            adapter = in.readParcelable(RemoteAnimationAdapter.class.getClassLoader());
+            activityTypeFilter = in.readInt();
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeParcelable(adapter, flags);
+            dest.writeInt(activityTypeFilter);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        private static final Creator<RemoteAnimationAdapterEntry> CREATOR
+                = new Creator<RemoteAnimationAdapterEntry>() {
+
+            @Override
+            public RemoteAnimationAdapterEntry createFromParcel(Parcel in) {
+                return new RemoteAnimationAdapterEntry(in);
+            }
+
+            @Override
+            public RemoteAnimationAdapterEntry[] newArray(int size) {
+                return new RemoteAnimationAdapterEntry[size];
+            }
+        };
+    }
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationDefinitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationDefinitionCompat.java
index 5fff5fe..098698a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationDefinitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationDefinitionCompat.java
@@ -29,6 +29,11 @@
         mWrapped.addRemoteAnimation(transition, adapter.getWrapped());
     }
 
+    public void addRemoteAnimation(int transition, int activityTypeFilter,
+            RemoteAnimationAdapterCompat adapter) {
+        mWrapped.addRemoteAnimation(transition, activityTypeFilter, adapter.getWrapped());
+    }
+
     RemoteAnimationDefinition getWrapped() {
         return mWrapped;
     }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
index a9c80c6..2de3ae2 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
@@ -18,6 +18,7 @@
 
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import android.app.WindowConfiguration;
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.RemoteException;
@@ -58,6 +59,8 @@
     public static final int TRANSIT_KEYGUARD_OCCLUDE = WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
     public static final int TRANSIT_KEYGUARD_UNOCCLUDE = WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
 
+    public static final int ACTIVITY_TYPE_STANDARD = WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+
     private static final WindowManagerWrapper sInstance = new WindowManagerWrapper();
 
     public static WindowManagerWrapper getInstance() {
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 40ee552..fc5e33a 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -52,6 +52,7 @@
 import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
 
+import android.app.WindowConfiguration;
 import android.os.Debug;
 import android.os.Trace;
 import android.util.ArraySet;
@@ -294,12 +295,14 @@
         // what will control the animation theme. If all closing windows are obscured, then there is
         // no need to do an animation. This is the case, for example, when this transition is being
         // done behind a dream window.
+        final ArraySet<Integer> activityTypes = collectActivityTypes(mService.mOpeningApps,
+                mService.mClosingApps);
         final AppWindowToken animLpToken = mService.mPolicy.allowAppAnimationsLw()
-                ? findAnimLayoutParamsToken(transit)
+                ? findAnimLayoutParamsToken(transit, activityTypes)
                 : null;
 
         final LayoutParams animLp = getAnimLp(animLpToken);
-        overrideWithRemoteAnimationIfSet(animLpToken, transit);
+        overrideWithRemoteAnimationIfSet(animLpToken, transit, activityTypes);
 
         final boolean voiceInteraction = containsVoiceInteraction(mService.mOpeningApps)
                 || containsVoiceInteraction(mService.mOpeningApps);
@@ -361,13 +364,14 @@
      * Overrides the pending transition with the remote animation defined for the transition in the
      * set of defined remote animations in the app window token.
      */
-    private void overrideWithRemoteAnimationIfSet(AppWindowToken animLpToken, int transit) {
+    private void overrideWithRemoteAnimationIfSet(AppWindowToken animLpToken, int transit,
+            ArraySet<Integer> activityTypes) {
         if (animLpToken == null) {
             return;
         }
         final RemoteAnimationDefinition definition = animLpToken.getRemoteAnimationDefinition();
         if (definition != null) {
-            final RemoteAnimationAdapter adapter = definition.getAdapter(transit);
+            final RemoteAnimationAdapter adapter = definition.getAdapter(transit, activityTypes);
             if (adapter != null) {
                 mService.mAppTransition.overridePendingAppTransitionRemote(adapter);
             }
@@ -377,13 +381,14 @@
     /**
      * @return The window token that determines the animation theme.
      */
-    private AppWindowToken findAnimLayoutParamsToken(@TransitionType int transit) {
+    private AppWindowToken findAnimLayoutParamsToken(@TransitionType int transit,
+            ArraySet<Integer> activityTypes) {
         AppWindowToken result;
 
         // Remote animations always win, but fullscreen tokens override non-fullscreen tokens.
         result = lookForHighestTokenWithFilter(mService.mClosingApps, mService.mOpeningApps,
                 w -> w.getRemoteAnimationDefinition() != null
-                        && w.getRemoteAnimationDefinition().hasTransition(transit));
+                        && w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes));
         if (result != null) {
             return result;
         }
@@ -396,6 +401,22 @@
                 w -> w.findMainWindow() != null);
     }
 
+    /**
+     * @return The set of {@link WindowConfiguration.ActivityType}s contained in the set of apps in
+     *         {@code array1} and {@code array2}.
+     */
+    private ArraySet<Integer> collectActivityTypes(ArraySet<AppWindowToken> array1,
+            ArraySet<AppWindowToken> array2) {
+        final ArraySet<Integer> result = new ArraySet<>();
+        for (int i = array1.size() - 1; i >= 0; i--) {
+            result.add(array1.valueAt(i).getActivityType());
+        }
+        for (int i = array2.size() - 1; i >= 0; i--) {
+            result.add(array2.valueAt(i).getActivityType());
+        }
+        return result;
+    }
+
     private AppWindowToken lookForHighestTokenWithFilter(ArraySet<AppWindowToken> array1,
             ArraySet<AppWindowToken> array2, Predicate<AppWindowToken> filter) {
         final int array1count = array1.size();
@@ -403,12 +424,9 @@
         int bestPrefixOrderIndex = Integer.MIN_VALUE;
         AppWindowToken bestToken = null;
         for (int i = 0; i < count; i++) {
-            final AppWindowToken wtoken;
-            if (i < array1count) {
-                wtoken = array1.valueAt(i);
-            } else {
-                wtoken = array2.valueAt(i - array1count);
-            }
+            final AppWindowToken wtoken = i < array1count
+                    ? array1.valueAt(i)
+                    : array2.valueAt(i - array1count);
             final int prefixOrderIndex = wtoken.getPrefixOrderIndex();
             if (filter.test(wtoken) && prefixOrderIndex > bestPrefixOrderIndex) {
                 bestPrefixOrderIndex = prefixOrderIndex;