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

Commit 19e2b248 authored by Vadim Caen's avatar Vadim Caen
Browse files

Create a builder class to create Surface Animatable

The SurfaceAnimator.Animatable interface can be cumbersome to implement
each time we want to animate a surface

For simple cases, this CL introduces a SimpleSurfaceAnimatable that is
instanciated using a builder pattern.

Test: N/A
Bug: N/A
Change-Id: I0e1d82f17b9a334c3c7362f7ebe42bcecbc9b48c
parent 184c4a86
Loading
Loading
Loading
Loading
+308 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.server.wm;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.view.SurfaceControl;

import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * An implementation of {@link SurfaceAnimator.Animatable} that is instantiated
 * using a builder pattern for more convenience over reimplementing the whole interface.
 * <p>
 * Use {@link SimpleSurfaceAnimatable.Builder} to create a new instance of this class.
 *
 * @see com.android.server.wm.SurfaceAnimator.Animatable
 */
public class SimpleSurfaceAnimatable implements SurfaceAnimator.Animatable {
    private final int mWidth;
    private final int mHeight;
    private final boolean mShouldDeferAnimationFinish;
    private final SurfaceControl mAnimationLeashParent;
    private final SurfaceControl mSurfaceControl;
    private final SurfaceControl mParentSurfaceControl;
    private final Runnable mCommitTransactionRunnable;
    private final Supplier<SurfaceControl.Builder> mAnimationLeashFactory;
    private final Supplier<SurfaceControl.Transaction> mPendingTransaction;
    private final BiConsumer<SurfaceControl.Transaction, SurfaceControl> mOnAnimationLeashCreated;
    private final Consumer<SurfaceControl.Transaction> mOnAnimationLeashLost;
    private final Consumer<Runnable> mOnAnimationFinished;

    /**
     * Use {@link SimpleSurfaceAnimatable.Builder} to create a new instance.
     */
    private SimpleSurfaceAnimatable(Builder builder) {
        mWidth = builder.mWidth;
        mHeight = builder.mHeight;
        mShouldDeferAnimationFinish = builder.mShouldDeferAnimationFinish;
        mAnimationLeashParent = builder.mAnimationLeashParent;
        mSurfaceControl = builder.mSurfaceControl;
        mParentSurfaceControl = builder.mParentSurfaceControl;
        mCommitTransactionRunnable = builder.mCommitTransactionRunnable;
        mAnimationLeashFactory = builder.mAnimationLeashFactory;
        mOnAnimationLeashCreated = builder.mOnAnimationLeashCreated;
        mOnAnimationLeashLost = builder.mOnAnimationLeashLost;
        mPendingTransaction = builder.mPendingTransactionSupplier;
        mOnAnimationFinished = builder.mOnAnimationFinished;
    }

    @NonNull
    @Override
    public SurfaceControl.Transaction getPendingTransaction() {
        return mPendingTransaction.get();
    }

    @Override
    public void commitPendingTransaction() {
        mCommitTransactionRunnable.run();
    }

    @Override
    public void onAnimationLeashCreated(SurfaceControl.Transaction t, SurfaceControl leash) {
        if (mOnAnimationLeashCreated != null) {
            mOnAnimationLeashCreated.accept(t, leash);
        }

    }

    @Override
    public void onAnimationLeashLost(SurfaceControl.Transaction t) {
        if (mOnAnimationLeashLost != null) {
            mOnAnimationLeashLost.accept(t);
        }
    }

    @Override
    @NonNull
    public SurfaceControl.Builder makeAnimationLeash() {
        return mAnimationLeashFactory.get();
    }

    @Override
    public SurfaceControl getAnimationLeashParent() {
        return mAnimationLeashParent;
    }

    @Override
    @Nullable
    public SurfaceControl getSurfaceControl() {
        return mSurfaceControl;
    }

    @Override
    public SurfaceControl getParentSurfaceControl() {
        return mParentSurfaceControl;
    }

    @Override
    public int getSurfaceWidth() {
        return mWidth;
    }

    @Override
    public int getSurfaceHeight() {
        return mHeight;
    }

    @Override
    public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
        if (mOnAnimationFinished != null) {
            mOnAnimationFinished.accept(endDeferFinishCallback);
        }
        return mShouldDeferAnimationFinish;
    }

    /**
     * Builder class to create a {@link SurfaceAnimator.Animatable} without having to
     * create a new class that implements the interface.
     */
    static class Builder {
        private int mWidth = -1;
        private int mHeight = -1;
        private boolean mShouldDeferAnimationFinish = false;

        @Nullable
        private SurfaceControl mAnimationLeashParent = null;

        @Nullable
        private SurfaceControl mSurfaceControl = null;

        @Nullable
        private SurfaceControl mParentSurfaceControl = null;
        private Runnable mCommitTransactionRunnable;

        @Nullable
        private BiConsumer<SurfaceControl.Transaction, SurfaceControl> mOnAnimationLeashCreated =
                null;

        @Nullable
        private Consumer<SurfaceControl.Transaction> mOnAnimationLeashLost = null;

        @Nullable
        private Consumer<Runnable> mOnAnimationFinished = null;

        @NonNull
        private Supplier<SurfaceControl.Transaction> mPendingTransactionSupplier;

        @NonNull
        private Supplier<SurfaceControl.Builder> mAnimationLeashFactory;

        /**
         * Set the runnable to be called when
         * {@link SurfaceAnimator.Animatable#commitPendingTransaction()}
         * is called.
         *
         * @see SurfaceAnimator.Animatable#commitPendingTransaction()
         */
        public SimpleSurfaceAnimatable.Builder setCommitTransactionRunnable(
                @NonNull Runnable commitTransactionRunnable) {
            mCommitTransactionRunnable = commitTransactionRunnable;
            return this;
        }

        /**
         * Set the callback called when
         * {@link SurfaceAnimator.Animatable#onAnimationLeashCreated(SurfaceControl.Transaction,
         * SurfaceControl)} is called
         *
         * @see SurfaceAnimator.Animatable#onAnimationLeashCreated(SurfaceControl.Transaction,
         * SurfaceControl)
         */
        public SimpleSurfaceAnimatable.Builder setOnAnimationLeashCreated(
                @Nullable BiConsumer<SurfaceControl.Transaction, SurfaceControl>
                        onAnimationLeashCreated) {
            mOnAnimationLeashCreated = onAnimationLeashCreated;
            return this;
        }

        /**
         * Set the callback called when
         * {@link SurfaceAnimator.Animatable#onAnimationLeashLost(SurfaceControl.Transaction)}
         * (SurfaceControl.Transaction, SurfaceControl)} is called
         *
         * @see SurfaceAnimator.Animatable#onAnimationLeashLost(SurfaceControl.Transaction)
         */
        public SimpleSurfaceAnimatable.Builder setOnAnimationLeashLost(
                @Nullable Consumer<SurfaceControl.Transaction> onAnimationLeashLost) {
            mOnAnimationLeashLost = onAnimationLeashLost;
            return this;
        }

        /**
         * @see SurfaceAnimator.Animatable#getPendingTransaction()
         */
        public Builder setPendingTransactionSupplier(
                @NonNull Supplier<SurfaceControl.Transaction> pendingTransactionSupplier) {
            mPendingTransactionSupplier = pendingTransactionSupplier;
            return this;
        }

        /**
         * Set the {@link Supplier} responsible for creating a new animation leash.
         *
         * @see SurfaceAnimator.Animatable#makeAnimationLeash()
         */
        public SimpleSurfaceAnimatable.Builder setAnimationLeashSupplier(
                @NonNull Supplier<SurfaceControl.Builder> animationLeashFactory) {
            mAnimationLeashFactory = animationLeashFactory;
            return this;
        }

        /**
         * @see SurfaceAnimator.Animatable#getAnimationLeashParent()
         */
        public SimpleSurfaceAnimatable.Builder setAnimationLeashParent(
                SurfaceControl animationLeashParent) {
            mAnimationLeashParent = animationLeashParent;
            return this;
        }

        /**
         * @see SurfaceAnimator.Animatable#getSurfaceControl()
         */
        public SimpleSurfaceAnimatable.Builder setSurfaceControl(
                @NonNull SurfaceControl surfaceControl) {
            mSurfaceControl = surfaceControl;
            return this;
        }

        /**
         * @see SurfaceAnimator.Animatable#getParentSurfaceControl()
         */
        public SimpleSurfaceAnimatable.Builder setParentSurfaceControl(
                SurfaceControl parentSurfaceControl) {
            mParentSurfaceControl = parentSurfaceControl;
            return this;
        }

        /**
         * Default to -1.
         *
         * @see SurfaceAnimator.Animatable#getSurfaceWidth()
         */
        public SimpleSurfaceAnimatable.Builder setWidth(int width) {
            mWidth = width;
            return this;
        }

        /**
         * Default to -1.
         *
         * @see SurfaceAnimator.Animatable#getSurfaceHeight()
         */
        public SimpleSurfaceAnimatable.Builder setHeight(int height) {
            mHeight = height;
            return this;
        }

        /**
         * Set the value returned by
         * {@link SurfaceAnimator.Animatable#shouldDeferAnimationFinish(Runnable)}.
         *
         * @param onAnimationFinish will be called with the runnable to execute when the animation
         *                          needs to be finished.
         * @see SurfaceAnimator.Animatable#shouldDeferAnimationFinish(Runnable)
         */
        public SimpleSurfaceAnimatable.Builder setShouldDeferAnimationFinish(
                boolean shouldDeferAnimationFinish,
                @Nullable Consumer<Runnable> onAnimationFinish) {
            mShouldDeferAnimationFinish = shouldDeferAnimationFinish;
            mOnAnimationFinished = onAnimationFinish;
            return this;
        }

        public SurfaceAnimator.Animatable build() {
            if (mPendingTransactionSupplier == null) {
                throw new IllegalArgumentException("mPendingTransactionSupplier cannot be null");
            }
            if (mAnimationLeashFactory == null) {
                throw new IllegalArgumentException("mAnimationLeashFactory cannot be null");
            }
            if (mCommitTransactionRunnable == null) {
                throw new IllegalArgumentException("mCommitTransactionRunnable cannot be null");
            }
            if (mSurfaceControl == null) {
                throw new IllegalArgumentException("mSurfaceControl cannot be null");
            }
            return new SimpleSurfaceAnimatable(this);
        }
    }
}