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

Commit 43c913bf authored by Taran Singh's avatar Taran Singh Committed by Android (Google) Code Review
Browse files

Merge "API update for insets"

parents 37ea48ad 54554e23
Loading
Loading
Loading
Loading
+74 −0
Original line number Diff line number Diff line
@@ -51082,6 +51082,9 @@ package android.view {
    method public boolean dispatchUnhandledMove(android.view.View, int);
    method protected void dispatchVisibilityChanged(@NonNull android.view.View, int);
    method public void dispatchWindowFocusChanged(boolean);
    method public void dispatchWindowInsetsAnimationFinished(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation);
    method @NonNull public android.view.WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull android.view.WindowInsets);
    method @NonNull public android.view.WindowInsetsAnimationCallback.AnimationBounds dispatchWindowInsetsAnimationStarted(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation, @NonNull android.view.WindowInsetsAnimationCallback.AnimationBounds);
    method public void dispatchWindowSystemUiVisiblityChanged(int);
    method public void dispatchWindowVisibilityChanged(int);
    method @CallSuper public void draw(android.graphics.Canvas);
@@ -51262,6 +51265,7 @@ package android.view {
    method @android.view.ViewDebug.ExportedProperty(category="layout") public final int getWidth();
    method protected int getWindowAttachCount();
    method public android.view.WindowId getWindowId();
    method @Nullable public android.view.WindowInsetsController getWindowInsetsController();
    method public int getWindowSystemUiVisibility();
    method public android.os.IBinder getWindowToken();
    method public int getWindowVisibility();
@@ -51600,6 +51604,7 @@ package android.view {
    method public void setVisibility(int);
    method @Deprecated public void setWillNotCacheDrawing(boolean);
    method public void setWillNotDraw(boolean);
    method public void setWindowInsetsAnimationCallback(@Nullable android.view.WindowInsetsAnimationCallback);
    method public void setX(float);
    method public void setY(float);
    method public void setZ(float);
@@ -52486,6 +52491,7 @@ package android.view {
    method public android.transition.Transition getExitTransition();
    method protected final int getFeatures();
    method protected final int getForcedWindowFlags();
    method @Nullable public android.view.WindowInsetsController getInsetsController();
    method @NonNull public abstract android.view.LayoutInflater getLayoutInflater();
    method protected final int getLocalFeatures();
    method public android.media.session.MediaController getMediaController();
@@ -52701,7 +52707,9 @@ package android.view {
    method @NonNull public android.view.WindowInsets consumeStableInsets();
    method @NonNull public android.view.WindowInsets consumeSystemWindowInsets();
    method @Nullable public android.view.DisplayCutout getDisplayCutout();
    method @NonNull public android.graphics.Insets getInsets(int);
    method @NonNull public android.graphics.Insets getMandatorySystemGestureInsets();
    method @NonNull public android.graphics.Insets getMaxInsets(int) throws java.lang.IllegalArgumentException;
    method public int getStableInsetBottom();
    method public int getStableInsetLeft();
    method public int getStableInsetRight();
@@ -52720,6 +52728,7 @@ package android.view {
    method @NonNull public android.view.WindowInsets inset(@IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int);
    method public boolean isConsumed();
    method public boolean isRound();
    method public boolean isVisible(int);
    method @Deprecated @NonNull public android.view.WindowInsets replaceSystemWindowInsets(int, int, int, int);
    method @Deprecated @NonNull public android.view.WindowInsets replaceSystemWindowInsets(android.graphics.Rect);
  }
@@ -52729,11 +52738,76 @@ package android.view {
    ctor public WindowInsets.Builder(@NonNull android.view.WindowInsets);
    method @NonNull public android.view.WindowInsets build();
    method @NonNull public android.view.WindowInsets.Builder setDisplayCutout(@Nullable android.view.DisplayCutout);
    method @NonNull public android.view.WindowInsets.Builder setInsets(int, @NonNull android.graphics.Insets);
    method @NonNull public android.view.WindowInsets.Builder setMandatorySystemGestureInsets(@NonNull android.graphics.Insets);
    method @NonNull public android.view.WindowInsets.Builder setMaxInsets(int, @NonNull android.graphics.Insets) throws java.lang.IllegalArgumentException;
    method @NonNull public android.view.WindowInsets.Builder setStableInsets(@NonNull android.graphics.Insets);
    method @NonNull public android.view.WindowInsets.Builder setSystemGestureInsets(@NonNull android.graphics.Insets);
    method @NonNull public android.view.WindowInsets.Builder setSystemWindowInsets(@NonNull android.graphics.Insets);
    method @NonNull public android.view.WindowInsets.Builder setTappableElementInsets(@NonNull android.graphics.Insets);
    method @NonNull public android.view.WindowInsets.Builder setVisible(int, boolean);
  }
  public static final class WindowInsets.Type {
    method public static int all();
    method public static int captionBar();
    method public static int ime();
    method public static int mandatorySystemGestures();
    method public static int navigationBars();
    method public static int statusBars();
    method public static int systemBars();
    method public static int systemGestures();
    method public static int tappableElement();
    method public static int windowDecor();
  }
  public interface WindowInsetsAnimationCallback {
    method public default void onFinished(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation);
    method @NonNull public android.view.WindowInsets onProgress(@NonNull android.view.WindowInsets);
    method @NonNull public default android.view.WindowInsetsAnimationCallback.AnimationBounds onStarted(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation, @NonNull android.view.WindowInsetsAnimationCallback.AnimationBounds);
  }
  public static final class WindowInsetsAnimationCallback.AnimationBounds {
    ctor public WindowInsetsAnimationCallback.AnimationBounds(@NonNull android.graphics.Insets, @NonNull android.graphics.Insets);
    method @NonNull public android.graphics.Insets getLowerBound();
    method @NonNull public android.graphics.Insets getUpperBound();
    method @NonNull public android.view.WindowInsetsAnimationCallback.AnimationBounds inset(@NonNull android.graphics.Insets);
  }
  public static final class WindowInsetsAnimationCallback.InsetsAnimation {
    ctor public WindowInsetsAnimationCallback.InsetsAnimation(int, @Nullable android.view.animation.Interpolator, long);
    method public long getDurationMillis();
    method @FloatRange(from=0.0f, to=1.0f) public float getFraction();
    method public float getInterpolatedFraction();
    method @Nullable public android.view.animation.Interpolator getInterpolator();
    method public int getTypeMask();
    method public void setDuration(long);
    method public void setFraction(@FloatRange(from=0.0f, to=1.0f) float);
  }
  public interface WindowInsetsAnimationControlListener {
    method public void onCancelled();
    method public void onReady(@NonNull android.view.WindowInsetsAnimationController, int);
  }
  public interface WindowInsetsAnimationController {
    method public void finish(boolean);
    method @FloatRange(from=0.0f, to=1.0f) public float getCurrentFraction();
    method @NonNull public android.graphics.Insets getCurrentInsets();
    method @NonNull public android.graphics.Insets getHiddenStateInsets();
    method @NonNull public android.graphics.Insets getShownStateInsets();
    method public int getTypes();
    method public void setInsetsAndAlpha(@Nullable android.graphics.Insets, @FloatRange(from=0.0f, to=1.0f) float, @FloatRange(from=0.0f, to=1.0f) float);
  }
  public interface WindowInsetsController {
    method public default void controlInputMethodAnimation(long, @NonNull android.view.WindowInsetsAnimationControlListener);
    method public default void hideInputMethod();
    method public void setSystemBarsAppearance(int);
    method public void setSystemBarsBehavior(int);
    method public default void showInputMethod();
    field public static final int APPEARANCE_LIGHT_NAVIGATION_BARS = 16; // 0x10
    field public static final int APPEARANCE_LIGHT_STATUS_BARS = 8; // 0x8
  }
  public interface WindowManager extends android.view.ViewManager {
+5 −4
Original line number Diff line number Diff line
@@ -16,13 +16,13 @@

package android.view;

import static android.view.DisplayEventReceiver.CONFIG_CHANGED_EVENT_SUPPRESS;
import static android.view.DisplayEventReceiver.VSYNC_SOURCE_APP;
import static android.view.DisplayEventReceiver.VSYNC_SOURCE_SURFACE_FLINGER;

import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.graphics.FrameInfo;
import android.graphics.Insets;
import android.hardware.display.DisplayManagerGlobal;
import android.os.Build;
import android.os.Handler;
@@ -219,9 +219,10 @@ public final class Choreographer {
    /**
     * Callback type: Animation callback to handle inset updates. This is separate from
     * {@link #CALLBACK_ANIMATION} as we need to "gather" all inset animation updates via
     * {@link WindowInsetsAnimationController#changeInsets} for multiple ongoing animations but then
     * update the whole view system with a single callback to {@link View#dispatchWindowInsetsAnimationProgress}
     * that contains all the combined updated insets.
     * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)} for multiple
     * ongoing animations but then update the whole view system with a single callback to
     * {@link View#dispatchWindowInsetsAnimationProgress} that contains all the combined updated
     * insets.
     * <p>
     * Both input and animation may change insets, so we need to run this after these callbacks, but
     * before traversals.
+34 −15
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import static android.view.InsetsState.ISIDE_FLOATING;
import static android.view.InsetsState.ISIDE_LEFT;
import static android.view.InsetsState.ISIDE_RIGHT;
import static android.view.InsetsState.ISIDE_TOP;
import static android.view.InsetsState.toPublicType;

import android.annotation.Nullable;
import android.graphics.Insets;
@@ -34,7 +33,8 @@ import android.util.SparseSetArray;
import android.view.InsetsState.InternalInsetsSide;
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimationListener.InsetsAnimation;
import android.view.WindowInsetsAnimationCallback.AnimationBounds;
import android.view.WindowInsetsAnimationCallback.InsetsAnimation;
import android.view.WindowManager.LayoutParams;

import com.android.internal.annotations.VisibleForTesting;
@@ -66,20 +66,21 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
    private final @InsetsType int mTypes;
    private final Supplier<SyncRtSurfaceTransactionApplier> mTransactionApplierSupplier;
    private final InsetsController mController;
    private final WindowInsetsAnimationListener.InsetsAnimation mAnimation;
    private final WindowInsetsAnimationCallback.InsetsAnimation mAnimation;
    private final Rect mFrame;
    private Insets mCurrentInsets;
    private Insets mPendingInsets;
    private float mPendingFraction;
    private boolean mFinished;
    private boolean mCancelled;
    private int mFinishedShownTypes;
    private boolean mShownOnFinish;

    @VisibleForTesting
    public InsetsAnimationControlImpl(SparseArray<InsetsSourceConsumer> consumers, Rect frame,
            InsetsState state, WindowInsetsAnimationControlListener listener,
            @InsetsType int types,
            Supplier<SyncRtSurfaceTransactionApplier> transactionApplierSupplier,
            InsetsController controller) {
            InsetsController controller, long durationMs) {
        mConsumers = consumers;
        mListener = listener;
        mTypes = types;
@@ -97,9 +98,10 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
        // TODO: Check for controllability first and wait for IME if needed.
        listener.onReady(this, types);

        mAnimation = new WindowInsetsAnimationListener.InsetsAnimation(mTypes, mHiddenInsets,
                mShownInsets);
        mController.dispatchAnimationStarted(mAnimation);
        mAnimation = new WindowInsetsAnimationCallback.InsetsAnimation(mTypes,
                InsetsController.INTERPOLATOR, durationMs);
        mController.dispatchAnimationStarted(mAnimation,
                new AnimationBounds(mHiddenInsets, mShownInsets));
    }

    @Override
@@ -123,7 +125,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
    }

    @Override
    public void changeInsets(Insets insets) {
    public void setInsetsAndAlpha(Insets insets, float alpha, float fraction) {
        if (mFinished) {
            throw new IllegalStateException(
                    "Can't change insets on an animation that is finished.");
@@ -132,6 +134,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
            throw new IllegalStateException(
                    "Can't change insets on an animation that is cancelled.");
        }
        mPendingFraction = sanitize(fraction);
        mPendingInsets = sanitize(insets);
        mController.scheduleApplyChangeInsets();
    }
@@ -155,30 +158,35 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
        SyncRtSurfaceTransactionApplier applier = mTransactionApplierSupplier.get();
        applier.scheduleApply(params.toArray(new SurfaceParams[params.size()]));
        mCurrentInsets = mPendingInsets;
        mAnimation.setFraction(mPendingFraction);
        if (mFinished) {
            mController.notifyFinished(this, mFinishedShownTypes);
            mController.notifyFinished(this, mShownOnFinish);
        }
        return mFinished;
    }

    @Override
    public void finish(int shownTypes) {
    public void finish(boolean shown) {
        if (mCancelled) {
            return;
        }
        InsetsState state = new InsetsState(mController.getState());
        for (int i = mConsumers.size() - 1; i >= 0; i--) {
            InsetsSourceConsumer consumer = mConsumers.valueAt(i);
            boolean visible = (shownTypes & toPublicType(consumer.getType())) != 0;
            state.getSource(consumer.getType()).setVisible(visible);
            state.getSource(consumer.getType()).setVisible(shown);
        }
        Insets insets = getInsetsFromState(state, mFrame, null /* typeSideMap */);
        changeInsets(insets);
        setInsetsAndAlpha(insets, 1f /* alpha */, shown ? 1f : 0f /* fraction */);
        mFinished = true;
        mFinishedShownTypes = shownTypes;
        mShownOnFinish = shown;
    }

    @Override
    @VisibleForTesting
    public float getCurrentFraction() {
        return mAnimation.getFraction();
    }

    public void onCancelled() {
        if (mFinished) {
            return;
@@ -191,6 +199,10 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
        return mAnimation;
    }

    WindowInsetsAnimationControlListener getListener() {
        return mListener;
    }

    private Insets calculateInsets(InsetsState state, Rect frame,
            SparseArray<InsetsSourceConsumer> consumers, boolean shown,
            @Nullable @InternalInsetsSide SparseIntArray typeSideMap) {
@@ -210,9 +222,16 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
    }

    private Insets sanitize(Insets insets) {
        if (insets == null) {
            insets = getCurrentInsets();
        }
        return Insets.max(Insets.min(insets, mShownInsets), mHiddenInsets);
    }

    private static float sanitize(float alpha) {
        return alpha >= 1 ? 1 : (alpha <= 0 ? 0 : alpha);
    }

    private void updateLeashesForSide(@InternalInsetsSide int side, int offset, int inset,
            ArrayList<SurfaceParams> surfaceParams, InsetsState state) {
        ArraySet<InsetsSourceConsumer> items = mSideSourceMap.get(side);
+92 −65
Original line number Diff line number Diff line
@@ -39,6 +39,8 @@ import android.view.InsetsState.InternalInsetsType;
import android.view.SurfaceControl.Transaction;
import android.view.WindowInsets.Type;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimationCallback.AnimationBounds;
import android.view.WindowInsetsAnimationCallback.InsetsAnimation;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;

@@ -55,11 +57,12 @@ public class InsetsController implements WindowInsetsController {

    private static final int ANIMATION_DURATION_SHOW_MS = 275;
    private static final int ANIMATION_DURATION_HIDE_MS = 340;
    private static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
    private static final int DIRECTION_NONE = 0;
    private static final int DIRECTION_SHOW = 1;
    private static final int DIRECTION_HIDE = 2;

    static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);

    @IntDef ({DIRECTION_NONE, DIRECTION_SHOW, DIRECTION_HIDE})
    private @interface AnimationDirection{}

@@ -85,8 +88,75 @@ public class InsetsController implements WindowInsetsController {
            return object.getCurrentInsets();
        }
        @Override
        public void set(WindowInsetsAnimationController object, Insets value) {
            object.changeInsets(value);
        public void set(WindowInsetsAnimationController controller, Insets value) {
            controller.setInsetsAndAlpha(
                    value, 1f /* alpha */, (((DefaultAnimationControlListener)
                            ((InsetsAnimationControlImpl) controller).getListener())
                                    .getRawProgress()));
        }
    }

    private class DefaultAnimationControlListener implements WindowInsetsAnimationControlListener {

        private WindowInsetsAnimationController mController;
        private ObjectAnimator mAnimator;
        private boolean mShow;

        DefaultAnimationControlListener(boolean show) {
            mShow = show;
        }

        @Override
        public void onReady(WindowInsetsAnimationController controller, int types) {
            mController = controller;
            if (mShow) {
                showDirectly(types);
            } else {
                hideDirectly(types);
            }
            mAnimationDirection = mShow ? DIRECTION_SHOW : DIRECTION_HIDE;
            mAnimator = ObjectAnimator.ofObject(
                    controller,
                    new InsetsProperty(),
                    sEvaluator,
                    mShow ? controller.getHiddenStateInsets() : controller.getShownStateInsets(),
                    mShow ? controller.getShownStateInsets() : controller.getHiddenStateInsets()
            );
            mAnimator.setDuration(getDurationMs());
            mAnimator.setInterpolator(INTERPOLATOR);
            mAnimator.addListener(new AnimatorListenerAdapter() {

                @Override
                public void onAnimationEnd(Animator animation) {
                    onAnimationFinish();
                }
            });
            mAnimator.start();
        }

        @Override
        public void onCancelled() {
            // Animator can be null when it is cancelled before onReady() completes.
            if (mAnimator != null) {
                mAnimator.cancel();
            }
        }

        private void onAnimationFinish() {
            mAnimationDirection = DIRECTION_NONE;
            mController.finish(mShow);
        }

        private float getRawProgress() {
            float fraction = (float) mAnimator.getCurrentPlayTime() / mAnimator.getDuration();
            return mShow ? fraction : 1 - fraction;
        }

        private long getDurationMs() {
            if (mAnimator != null) {
                return mAnimator.getDuration();
            }
            return mShow ? ANIMATION_DURATION_SHOW_MS : ANIMATION_DURATION_HIDE_MS;
        }
    }

@@ -278,24 +348,25 @@ public class InsetsController implements WindowInsetsController {
    }

    @Override
    public void controlWindowInsetsAnimation(@InsetsType int types,
    public void controlWindowInsetsAnimation(@InsetsType int types, long durationMs,
            WindowInsetsAnimationControlListener listener) {
        controlWindowInsetsAnimation(types, listener, false /* fromIme */);
        controlWindowInsetsAnimation(types, listener, false /* fromIme */, durationMs);
    }

    private void controlWindowInsetsAnimation(@InsetsType int types,
            WindowInsetsAnimationControlListener listener, boolean fromIme) {
            WindowInsetsAnimationControlListener listener, boolean fromIme, long durationMs) {
        // If the frame of our window doesn't span the entire display, the control API makes very
        // little sense, as we don't deal with negative insets. So just cancel immediately.
        if (!mState.getDisplayFrame().equals(mFrame)) {
            listener.onCancelled();
            return;
        }
        controlAnimationUnchecked(types, listener, mFrame, fromIme);
        controlAnimationUnchecked(types, listener, mFrame, fromIme, durationMs);
    }

    private void controlAnimationUnchecked(@InsetsType int types,
            WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme) {
            WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme,
            long durationMs) {
        if (types == 0) {
            // nothing to animate.
            return;
@@ -326,7 +397,7 @@ public class InsetsController implements WindowInsetsController {

        final InsetsAnimationControlImpl controller = new InsetsAnimationControlImpl(consumers,
                frame, mState, listener, typesReady,
                () -> new SyncRtSurfaceTransactionApplier(mViewRoot.mView), this);
                () -> new SyncRtSurfaceTransactionApplier(mViewRoot.mView), this, durationMs);
        mAnimationControls.add(controller);
    }

@@ -397,10 +468,13 @@ public class InsetsController implements WindowInsetsController {
    }

    @VisibleForTesting
    public void notifyFinished(InsetsAnimationControlImpl controller, int shownTypes) {
    public void notifyFinished(InsetsAnimationControlImpl controller, boolean shown) {
        mAnimationControls.remove(controller);
        hideDirectly(controller.getTypes() & ~shownTypes);
        showDirectly(controller.getTypes() & shownTypes);
        if (shown) {
            showDirectly(controller.getTypes());
        } else {
            hideDirectly(controller.getTypes());
        }
    }

    void notifyControlRevoked(InsetsSourceConsumer consumer) {
@@ -510,58 +584,11 @@ public class InsetsController implements WindowInsetsController {
            return;
        }

        WindowInsetsAnimationControlListener listener = new WindowInsetsAnimationControlListener() {

            private WindowInsetsAnimationController mController;
            private ObjectAnimator mAnimator;

            @Override
            public void onReady(WindowInsetsAnimationController controller, int types) {
                mController = controller;
                if (show) {
                    showDirectly(types);
                } else {
                    hideDirectly(types);
                }
                mAnimationDirection = show ? DIRECTION_SHOW : DIRECTION_HIDE;
                mAnimator = ObjectAnimator.ofObject(
                        controller,
                        new InsetsProperty(),
                        sEvaluator,
                        show ? controller.getHiddenStateInsets() : controller.getShownStateInsets(),
                        show ? controller.getShownStateInsets() : controller.getHiddenStateInsets()
                );
                mAnimator.setDuration(show
                        ? ANIMATION_DURATION_SHOW_MS
                        : ANIMATION_DURATION_HIDE_MS);
                mAnimator.setInterpolator(INTERPOLATOR);
                mAnimator.addListener(new AnimatorListenerAdapter() {

                    @Override
                    public void onAnimationEnd(Animator animation) {
                        onAnimationFinish();
                    }
                });
                mAnimator.start();
            }

            @Override
            public void onCancelled() {
                // Animator can be null when it is cancelled before onReady() completes.
                if (mAnimator != null) {
                    mAnimator.cancel();
                }
            }

            private void onAnimationFinish() {
                mAnimationDirection = DIRECTION_NONE;
                mController.finish(show ? types : 0);
            }
        };

        final DefaultAnimationControlListener listener = new DefaultAnimationControlListener(show);
        // Show/hide animations always need to be relative to the display frame, in order that shown
        // and hidden state insets are correct.
        controlAnimationUnchecked(types, listener, mState.getDisplayFrame(), fromIme);
        controlAnimationUnchecked(
                types, listener, mState.getDisplayFrame(), fromIme, listener.getDurationMs());
    }

    private void hideDirectly(@InsetsType int types) {
@@ -592,12 +619,12 @@ public class InsetsController implements WindowInsetsController {
    }

    @VisibleForTesting
    public void dispatchAnimationStarted(WindowInsetsAnimationListener.InsetsAnimation animation) {
        mViewRoot.mView.dispatchWindowInsetsAnimationStarted(animation);
    public void dispatchAnimationStarted(InsetsAnimation animation, AnimationBounds bounds) {
        mViewRoot.mView.dispatchWindowInsetsAnimationStarted(animation, bounds);
    }

    @VisibleForTesting
    public void dispatchAnimationFinished(WindowInsetsAnimationListener.InsetsAnimation animation) {
    public void dispatchAnimationFinished(InsetsAnimation animation) {
        mViewRoot.mView.dispatchWindowInsetsAnimationFinished(animation);
    }

+38 −16

File changed.

Preview size limit exceeded, changes collapsed.

Loading