Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c1756316 authored by Jorim Jaggi's avatar Jorim Jaggi Committed by Android (Google) Code Review
Browse files

Merge "Add ability to filter remote animation adapter by activity type" into pi-dev

parents 41b5ece1 77be157a
Loading
Loading
Loading
Loading
+101 −10
Original line number Diff line number Diff line
@@ -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 @@ import android.view.WindowManager.TransitionType;
 */
public class RemoteAnimationDefinition implements Parcelable {

    private final SparseArray<RemoteAnimationAdapter> mTransitionAnimationMap;
    private final SparseArray<RemoteAnimationAdapterEntry> mTransitionAnimationMap;

    public RemoteAnimationDefinition() {
        mTransitionAnimationMap = new SparseArray<>();
@@ -40,34 +44,70 @@ public class RemoteAnimationDefinition implements Parcelable {
     * 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 class RemoteAnimationDefinition implements Parcelable {
     */
    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 @@ public class RemoteAnimationDefinition implements Parcelable {

    @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 @@ public class RemoteAnimationDefinition implements Parcelable {
            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];
            }
        };
    }
}
+5 −0
Original line number Diff line number Diff line
@@ -29,6 +29,11 @@ public class RemoteAnimationDefinitionCompat {
        mWrapped.addRemoteAnimation(transition, adapter.getWrapped());
    }

    public void addRemoteAnimation(int transition, int activityTypeFilter,
            RemoteAnimationAdapterCompat adapter) {
        mWrapped.addRemoteAnimation(transition, activityTypeFilter, adapter.getWrapped());
    }

    RemoteAnimationDefinition getWrapped() {
        return mWrapped;
    }
+3 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.systemui.shared.system;

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 class WindowManagerWrapper {
    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() {
+30 −12
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ import static com.android.server.wm.WindowManagerService.H.REPORT_WINDOWS_CHANGE
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 @@ class WindowSurfacePlacer {
        // 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 @@ class WindowSurfacePlacer {
     * 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 @@ class WindowSurfacePlacer {
    /**
     * @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 @@ class WindowSurfacePlacer {
                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 @@ class WindowSurfacePlacer {
        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;