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

Commit 33a701a5 authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

Remote animations (app-controlled animations)

Adds the ability for another app to control an entire app
transition. It does so by creating an ActivityOptions object that
contains a RemoteAnimationAdapter object that describes how the
animation should be run: Along of some meta-data, this object
contains a callback that gets invoked from WM when the transition
is ready to be started.

Window manager supplies a list of RemoteAnimationApps into the
callback. Each app contains information about the app as well as
the animation leash. The controlling app can modify the leash like
any other surface, including the possibility to synchronize
updating the leash's surface properties with a frame to be drawn
using the Transaction.deferUntil API.

When the animation is done, the app can invoke the finished
callback to get WM out of the animating state, which will also
clean up any closing apps.

We use a timeout of 2000ms such that a buggy controlling app can
not break window manager forever (duration subject to change).

Test: go/wm-smoke
Test: RemoteAnimationControllerTest

Bug: 64674361
Change-Id: I34e0c9a91b28badebac74896f95c6390f1b947ab
parent 4876b4a2
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -324,6 +324,8 @@ java_library {
        "core/java/android/view/IOnKeyguardExitResult.aidl",
        "core/java/android/view/IPinnedStackController.aidl",
        "core/java/android/view/IPinnedStackListener.aidl",
        "core/java/android/view/IRemoteAnimationRunner.aidl",
        "core/java/android/view/IRemoteAnimationFinishedCallback.aidl",
        "core/java/android/view/IRotationWatcher.aidl",
        "core/java/android/view/IWallpaperVisibilityListener.aidl",
        "core/java/android/view/IWindow.aidl",
+32 −1
Original line number Diff line number Diff line
@@ -16,12 +16,14 @@

package android.app;

import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Display.INVALID_DISPLAY;

import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.TestApi;
import android.content.ComponentName;
import android.content.Context;
@@ -44,6 +46,7 @@ import android.util.Pair;
import android.util.Slog;
import android.view.AppTransitionAnimationSpec;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.RemoteAnimationAdapter;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
@@ -241,6 +244,8 @@ public class ActivityOptions {
    private static final String KEY_INSTANT_APP_VERIFICATION_BUNDLE
            = "android:instantapps.installerbundle";
    private static final String KEY_SPECS_FUTURE = "android:activity.specsFuture";
    private static final String KEY_REMOTE_ANIMATION_ADAPTER
            = "android:activity.remoteAnimationAdapter";

    /** @hide */
    public static final int ANIM_NONE = 0;
@@ -268,6 +273,8 @@ public class ActivityOptions {
    public static final int ANIM_CLIP_REVEAL = 11;
    /** @hide */
    public static final int ANIM_OPEN_CROSS_PROFILE_APPS = 12;
    /** @hide */
    public static final int ANIM_REMOTE_ANIMATION = 13;

    private String mPackageName;
    private Rect mLaunchBounds;
@@ -304,6 +311,7 @@ public class ActivityOptions {
    private int mRotationAnimationHint = -1;
    private Bundle mAppVerificationBundle;
    private IAppTransitionAnimationSpecsFuture mSpecsFuture;
    private RemoteAnimationAdapter mRemoteAnimationAdapter;

    /**
     * Create an ActivityOptions specifying a custom animation to run when
@@ -826,6 +834,20 @@ public class ActivityOptions {
        return opts;
    }

    /**
     * Create an {@link ActivityOptions} instance that lets the application control the entire
     * animation using a {@link RemoteAnimationAdapter}.
     * @hide
     */
    @RequiresPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS)
    public static ActivityOptions makeRemoteAnimation(
            RemoteAnimationAdapter remoteAnimationAdapter) {
        final ActivityOptions opts = new ActivityOptions();
        opts.mRemoteAnimationAdapter = remoteAnimationAdapter;
        opts.mAnimationType = ANIM_REMOTE_ANIMATION;
        return opts;
    }

    /** @hide */
    public boolean getLaunchTaskBehind() {
        return mAnimationType == ANIM_LAUNCH_TASK_BEHIND;
@@ -922,6 +944,7 @@ public class ActivityOptions {
            mSpecsFuture = IAppTransitionAnimationSpecsFuture.Stub.asInterface(opts.getBinder(
                    KEY_SPECS_FUTURE));
        }
        mRemoteAnimationAdapter = opts.getParcelable(KEY_REMOTE_ANIMATION_ADAPTER);
    }

    /**
@@ -1069,6 +1092,11 @@ public class ActivityOptions {
        return mSpecsFuture;
    }

    /** @hide */
    public RemoteAnimationAdapter getRemoteAnimationAdapter() {
        return mRemoteAnimationAdapter;
    }

    /** @hide */
    public static ActivityOptions fromBundle(Bundle bOptions) {
        return bOptions != null ? new ActivityOptions(bOptions) : null;
@@ -1309,6 +1337,7 @@ public class ActivityOptions {
        mAnimSpecs = otherOptions.mAnimSpecs;
        mAnimationFinishedListener = otherOptions.mAnimationFinishedListener;
        mSpecsFuture = otherOptions.mSpecsFuture;
        mRemoteAnimationAdapter = otherOptions.mRemoteAnimationAdapter;
    }

    /**
@@ -1403,7 +1432,9 @@ public class ActivityOptions {
        if (mAppVerificationBundle != null) {
            b.putBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE, mAppVerificationBundle);
        }

        if (mRemoteAnimationAdapter != null) {
            b.putParcelable(KEY_REMOTE_ANIMATION_ADAPTER, mRemoteAnimationAdapter);
        }
        return b;
    }

+27 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License
 */

package android.view;

/**
 * Interface to be invoked by the controlling process when a remote animation has finished.
 *
 * @see IRemoteAnimationRunner
 * {@hide}
 */
interface IRemoteAnimationFinishedCallback {
    void onAnimationFinished();
}
+44 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view;

import android.view.RemoteAnimationTarget;
import android.view.IRemoteAnimationFinishedCallback;

/**
 * Interface that is used to callback from window manager to the process that runs a remote
 * animation to start or cancel it.
 *
 * {@hide}
 */
oneway interface IRemoteAnimationRunner {

    /**
     * Called when the process needs to start the remote animation.
     *
     * @param apps The list of apps to animate.
     * @param finishedCallback The callback to invoke when the animation is finished.
     */
    void onAnimationStart(in RemoteAnimationTarget[] apps,
            in IRemoteAnimationFinishedCallback finishedCallback);

    /**
     * Called when the animation was cancelled. From this point on, any updates onto the leashes
     * won't have any effect anymore.
     */
    void onAnimationCancelled();
}
+2 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IDockedStackListener;
import android.view.IOnKeyguardExitResult;
import android.view.IPinnedStackListener;
import android.view.RemoteAnimationAdapter;
import android.view.IRotationWatcher;
import android.view.IWallpaperVisibilityListener;
import android.view.IWindowSession;
@@ -124,6 +125,7 @@ interface IWindowManager
    void overridePendingAppTransitionMultiThumbFuture(
            IAppTransitionAnimationSpecsFuture specsFuture, IRemoteCallback startedCallback,
            boolean scaleUp);
    void overridePendingAppTransitionRemote(in RemoteAnimationAdapter remoteAnimationAdapter);
    void executeAppTransition();

    /** Used by system ui to report that recents has shown itself. */
Loading