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

Commit b65d766d authored by Sunny Goyal's avatar Sunny Goyal
Browse files

Adding support for listening for app launch animation completion

Bug: 181165935
Bug: 179065491
Test: Verified on device
Change-Id: Ifa6a91560cb31b4dfb72a0f582607e873d8a002d
parent 462384db
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -17,8 +17,6 @@
<!-- Class overrides for launcher with quickstep. -->

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
  <string name="app_transition_manager_class" translatable="false">com.android.launcher3.LauncherAppTransitionManagerImpl</string>

  <string name="instant_app_resolver_class" translatable="false">com.android.quickstep.InstantAppResolverImpl</string>

  <string name="app_launch_tracker_class" translatable="false">com.android.launcher3.appprediction.PredictionAppTracker</string>
+25 −8
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@ import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SY

import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.app.ActivityOptions;
import android.content.Intent;
import android.content.IntentSender;
import android.os.Bundle;
@@ -47,6 +46,7 @@ import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.launcher3.taskbar.TaskbarController;
import com.android.launcher3.taskbar.TaskbarStateHandler;
import com.android.launcher3.uioverrides.RecentsViewStateController;
import com.android.launcher3.util.ActivityOptionsWrapper;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.UiThreadHelper;
import com.android.quickstep.RecentsModel;
@@ -73,6 +73,7 @@ public abstract class BaseQuickstepLauncher extends Launcher
        implements NavigationModeChangeListener {

    private DepthController mDepthController = new DepthController(this);
    private QuickstepTransitionManager mAppTransitionManager;

    /**
     * Reusable command for applying the back button alpha on the background thread.
@@ -91,6 +92,8 @@ public abstract class BaseQuickstepLauncher extends Launcher
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mAppTransitionManager = new QuickstepTransitionManager(this);
        mAppTransitionManager.registerRemoteAnimations();

        SysUINavigationMode.INSTANCE.get(this).addModeChangeListener(this);
        addMultiWindowModeChangedListener(mDepthController);
@@ -98,8 +101,9 @@ public abstract class BaseQuickstepLauncher extends Launcher

    @Override
    public void onDestroy() {
        SysUINavigationMode.INSTANCE.get(this).removeModeChangeListener(this);
        mAppTransitionManager.onActivityDestroyed();

        SysUINavigationMode.INSTANCE.get(this).removeModeChangeListener(this);
        if (mTaskbarController != null) {
            mTaskbarController.cleanup();
        }
@@ -107,6 +111,10 @@ public abstract class BaseQuickstepLauncher extends Launcher
        super.onDestroy();
    }

    public QuickstepTransitionManager getAppTransitionManager() {
        return mAppTransitionManager;
    }

    @Override
    public void onNavigationModeChanged(Mode newMode) {
        getDragLayer().recreateControllers();
@@ -270,6 +278,12 @@ public abstract class BaseQuickstepLauncher extends Launcher
        return mTaskbarController != null && mTaskbarController.isViewInTaskbar(v);
    }

    public boolean supportsAdaptiveIconAnimation(View clickedView) {
        return mAppTransitionManager.hasControlRemoteAppTransitionPermission()
                && FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM.get()
                && !isViewInTaskbar(clickedView);
    }

    @Override
    public DragOptions getDefaultWorkspaceDragOptions() {
        if (mNextWorkspaceDragOptions != null) {
@@ -286,8 +300,7 @@ public abstract class BaseQuickstepLauncher extends Launcher

    @Override
    public void useFadeOutAnimationForLauncherStart(CancellationSignal signal) {
        QuickstepAppTransitionManagerImpl appTransitionManager =
                (QuickstepAppTransitionManagerImpl) getAppTransitionManager();
        QuickstepTransitionManager appTransitionManager = getAppTransitionManager();
        appTransitionManager.setRemoteAnimationProvider(new RemoteAnimationProvider() {
            @Override
            public AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets,
@@ -379,10 +392,14 @@ public abstract class BaseQuickstepLauncher extends Launcher
    }

    @Override
    public ActivityOptions getActivityLaunchOptions(View v) {
        ActivityOptions activityOptions = super.getActivityLaunchOptions(v);
        if (activityOptions != null && mLastTouchUpTime > 0) {
            ActivityOptionsCompat.setLauncherSourceInfo(activityOptions, mLastTouchUpTime);
    public ActivityOptionsWrapper getActivityLaunchOptions(View v) {
        ActivityOptionsWrapper activityOptions =
                mAppTransitionManager.hasControlRemoteAppTransitionPermission()
                        ? mAppTransitionManager.getActivityLaunchOptions(this, v)
                        : super.getActivityLaunchOptions(v);
        if (mLastTouchUpTime > 0) {
            ActivityOptionsCompat.setLauncherSourceInfo(
                    activityOptions.options, mLastTouchUpTime);
        }
        return activityOptions;
    }
+30 −10
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ package com.android.launcher3;

import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.systemui.shared.recents.utilities.Utilities.postAtFrontOfQueueAsynchronously;

@@ -29,6 +30,7 @@ import android.os.Build;
import android.os.Handler;

import androidx.annotation.BinderThread;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;

import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
@@ -37,8 +39,6 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@TargetApi(Build.VERSION_CODES.P)
public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat {

    private static final String TAG = "LauncherAnimationRunner";

    private final Handler mHandler;
    private final boolean mStartAtFrontOfQueue;
    private AnimationResult mAnimationResult;
@@ -66,10 +66,7 @@ public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCo
            Runnable runnable) {
        Runnable r = () -> {
            finishExistingAnimation();
            mAnimationResult = new AnimationResult(() -> {
                UI_HELPER_EXECUTOR.execute(runnable);
                mAnimationResult = null;
            });
            mAnimationResult = new AnimationResult(() -> mAnimationResult = null, runnable);
            onCreateAnimation(transit, appTargets, wallpaperTargets, nonAppTargets,
                    mAnimationResult);
        };
@@ -126,37 +123,60 @@ public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCo

    public static final class AnimationResult {

        private final Runnable mFinishRunnable;
        private final Runnable mSyncFinishRunnable;
        private final Runnable mASyncFinishRunnable;

        private AnimatorSet mAnimator;
        private Runnable mOnCompleteCallback;
        private boolean mFinished = false;
        private boolean mInitialized = false;

        private AnimationResult(Runnable finishRunnable) {
            mFinishRunnable = finishRunnable;
        private AnimationResult(Runnable syncFinishRunnable, Runnable asyncFinishRunnable) {
            mSyncFinishRunnable = syncFinishRunnable;
            mASyncFinishRunnable = asyncFinishRunnable;
        }

        @UiThread
        private void finish() {
            if (!mFinished) {
                mFinishRunnable.run();
                mSyncFinishRunnable.run();
                UI_HELPER_EXECUTOR.execute(() -> {
                    mASyncFinishRunnable.run();
                    if (mOnCompleteCallback != null) {
                        MAIN_EXECUTOR.execute(mOnCompleteCallback);
                    }
                });
                mFinished = true;
            }
        }

        @UiThread
        public void setAnimation(AnimatorSet animation, Context context) {
            setAnimation(animation, context, null);

        }

        /**
         * Sets the animation to play for this app launch
         */
        @UiThread
        public void setAnimation(AnimatorSet animation, Context context,
                @Nullable Runnable onCompleteCallback) {
            if (mInitialized) {
                throw new IllegalStateException("Animation already initialized");
            }
            mInitialized = true;
            mAnimator = animation;
            mOnCompleteCallback = onCompleteCallback;
            if (mAnimator == null) {
                finish();
            } else if (mFinished) {
                // Animation callback was already finished, skip the animation.
                mAnimator.start();
                mAnimator.end();
                if (mOnCompleteCallback != null) {
                    mOnCompleteCallback.run();
                }
            } else {
                // Start the animation
                mAnimator.addListener(new AnimatorListenerAdapter() {
+0 −83
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 com.android.launcher3;

import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;

import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.quickstep.TaskViewUtils;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;

/**
 * A {@link QuickstepAppTransitionManagerImpl} that also implements recents transitions from
 * {@link RecentsView}.
 */
public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransitionManagerImpl {

    public LauncherAppTransitionManagerImpl(Context context) {
        super(context);
    }

    @Override
    protected boolean isLaunchingFromRecents(@NonNull View v,
            @Nullable RemoteAnimationTargetCompat[] targets) {
        return mLauncher.getStateManager().getState().overviewUi
                && findTaskViewToLaunch(mLauncher.getOverviewPanel(), v, targets) != null;
    }

    @Override
    protected void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v,
            @NonNull RemoteAnimationTargetCompat[] appTargets,
            @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, boolean launcherClosing) {
        TaskViewUtils.composeRecentsLaunchAnimator(anim, v, appTargets, wallpaperTargets,
                launcherClosing, mLauncher.getStateManager(), mLauncher.getOverviewPanel(),
                mLauncher.getDepthController());
    }

    @Override
    protected Runnable composeViewContentAnimator(@NonNull AnimatorSet anim, float[] alphas,
            float[] trans) {
        RecentsView overview = mLauncher.getOverviewPanel();
        ObjectAnimator alpha = ObjectAnimator.ofFloat(overview,
                RecentsView.CONTENT_ALPHA, alphas);
        alpha.setDuration(CONTENT_ALPHA_DURATION);
        alpha.setInterpolator(LINEAR);
        anim.play(alpha);
        overview.setFreezeViewVisibility(true);

        ObjectAnimator transY = ObjectAnimator.ofFloat(overview, View.TRANSLATION_Y, trans);
        transY.setInterpolator(AGGRESSIVE_EASE);
        transY.setDuration(CONTENT_TRANSLATION_DURATION);
        anim.play(transY);

        return () -> {
            overview.setFreezeViewVisibility(false);
            overview.setTranslationY(0);
            mLauncher.getStateManager().reapplyState();
        };
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -46,8 +46,8 @@ public class LauncherInitListener extends ActivityInitListener<Launcher> {
    @Override
    public boolean handleInit(Launcher launcher, boolean alreadyOnHome) {
        if (mRemoteAnimationProvider != null) {
            QuickstepAppTransitionManagerImpl appTransitionManager =
                    (QuickstepAppTransitionManagerImpl) launcher.getAppTransitionManager();
            QuickstepTransitionManager appTransitionManager =
                    ((BaseQuickstepLauncher) launcher).getAppTransitionManager();

            // Set a one-time animation provider. After the first call, this will get cleared.
            // TODO: Probably also check the intended target id.
Loading