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

Commit 839ca430 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 9635238 from b8b7a230 to tm-qpr3-release

Change-Id: Ib88dd0738d83f9e9b40646d53b46f30ea04684e5
parents ef8780d0 b8b7a230
Loading
Loading
Loading
Loading
+105 −61
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ import android.hardware.display.DisplayManager.DisplayListener;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
@@ -180,6 +181,9 @@ public abstract class WallpaperService extends Service {
    private final ArrayList<Engine> mActiveEngines
            = new ArrayList<Engine>();

    private Handler mBackgroundHandler;
    private HandlerThread mBackgroundThread;

    static final class WallpaperCommand {
        String action;
        int x;
@@ -198,14 +202,6 @@ public abstract class WallpaperService extends Service {
     */
    public class Engine {
        IWallpaperEngineWrapper mIWallpaperEngine;
        final ArraySet<RectF> mLocalColorAreas = new ArraySet<>(4);
        final ArraySet<RectF> mLocalColorsToAdd = new ArraySet<>(4);

        // 2D matrix [x][y] to represent a page of a portion of a window
        EngineWindowPage[] mWindowPages = new EngineWindowPage[0];
        Bitmap mLastScreenshot;
        int mLastWindowPage = -1;
        private boolean mResetWindowPages;

        // Copies from mIWallpaperEngine.
        HandlerCaller mCaller;
@@ -267,11 +263,27 @@ public abstract class WallpaperService extends Service {

        final Object mLock = new Object();
        boolean mOffsetMessageEnqueued;

        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
        float mPendingXOffset;
        float mPendingYOffset;
        float mPendingXOffsetStep;
        float mPendingYOffsetStep;

        /**
         * local color extraction related fields
         * to be used by the background thread only (except the atomic boolean)
         */
        final ArraySet<RectF> mLocalColorAreas = new ArraySet<>(4);
        final ArraySet<RectF> mLocalColorsToAdd = new ArraySet<>(4);
        private long mLastProcessLocalColorsTimestamp;
        private AtomicBoolean mProcessLocalColorsPending = new AtomicBoolean(false);
        private int mPixelCopyCount = 0;
        // 2D matrix [x][y] to represent a page of a portion of a window
        EngineWindowPage[] mWindowPages = new EngineWindowPage[0];
        Bitmap mLastScreenshot;
        private boolean mResetWindowPages;

        boolean mPendingSync;
        MotionEvent mPendingMove;
        boolean mIsInAmbientMode;
@@ -280,12 +292,8 @@ public abstract class WallpaperService extends Service {
        private long mLastColorInvalidation;
        private final Runnable mNotifyColorsChanged = this::notifyColorsChanged;

        // used to throttle processLocalColors
        private long mLastProcessLocalColorsTimestamp;
        private AtomicBoolean mProcessLocalColorsPending = new AtomicBoolean(false);
        private final Supplier<Long> mClockFunction;
        private final Handler mHandler;

        private Display mDisplay;
        private Context mDisplayContext;
        private int mDisplayState;
@@ -825,7 +833,7 @@ public abstract class WallpaperService extends Service {
                            + "was not established.");
                }
                mResetWindowPages = true;
                processLocalColors(mPendingXOffset, mPendingXOffsetStep);
                processLocalColors();
            } catch (RemoteException e) {
                Log.w(TAG, "Can't notify system because wallpaper connection was lost.", e);
            }
@@ -1364,7 +1372,7 @@ public abstract class WallpaperService extends Service {
                            resetWindowPages();
                            mSession.finishDrawing(mWindow, null /* postDrawTransaction */,
                                                   Integer.MAX_VALUE);
                            processLocalColors(mPendingXOffset, mPendingXOffsetStep);
                            processLocalColors();
                        }
                        reposition();
                        reportEngineShown(shouldWaitForEngineShown());
@@ -1509,7 +1517,7 @@ public abstract class WallpaperService extends Service {
            if (!mDestroyed) {
                mVisible = visible;
                reportVisibility();
                if (mReportedVisible) processLocalColors(mPendingXOffset, mPendingXOffsetStep);
                if (mReportedVisible) processLocalColors();
            } else {
                AnimationHandler.requestAnimatorsEnabled(visible, this);
            }
@@ -1593,31 +1601,41 @@ public abstract class WallpaperService extends Service {
            }

            // setup local color extraction data
            processLocalColors(xOffset, xOffsetStep);
            processLocalColors();
        }

        /**
         * Thread-safe util to call {@link #processLocalColorsInternal} with a minimum interval of
         * {@link #PROCESS_LOCAL_COLORS_INTERVAL_MS} between two calls.
         */
        private void processLocalColors(float xOffset, float xOffsetStep) {
        private void processLocalColors() {
            if (mProcessLocalColorsPending.compareAndSet(false, true)) {
                final long now = mClockFunction.get();
                final long timeSinceLastColorProcess = now - mLastProcessLocalColorsTimestamp;
                final long timeToWait = Math.max(0,
                        PROCESS_LOCAL_COLORS_INTERVAL_MS - timeSinceLastColorProcess);

                mHandler.postDelayed(() -> {
                mBackgroundHandler.postDelayed(() -> {
                    mLastProcessLocalColorsTimestamp = now + timeToWait;
                    mProcessLocalColorsPending.set(false);
                    processLocalColorsInternal(xOffset, xOffsetStep);
                    processLocalColorsInternal();
                }, timeToWait);
            }
        }

        private void processLocalColorsInternal(float xOffset, float xOffsetStep) {
        private void processLocalColorsInternal() {
            // implemented by the wallpaper
            if (supportsLocalColorExtraction()) return;
            assertBackgroundThread();
            float xOffset;
            float xOffsetStep;
            float wallpaperDimAmount;
            synchronized (mLock) {
                xOffset = mPendingXOffset;
                xOffsetStep = mPendingXOffsetStep;
                wallpaperDimAmount = mWallpaperDimAmount;
            }

            if (DEBUG) {
                Log.d(TAG, "processLocalColors " + xOffset + " of step "
                        + xOffsetStep);
@@ -1680,7 +1698,7 @@ public abstract class WallpaperService extends Service {
                xPage = mWindowPages.length - 1;
            }
            current = mWindowPages[xPage];
            updatePage(current, xPage, xPages, finalXOffsetStep);
            updatePage(current, xPage, xPages, wallpaperDimAmount);
            Trace.endSection();
        }

@@ -1700,16 +1718,23 @@ public abstract class WallpaperService extends Service {
            }
        }

        /**
         * Must be called with the surface lock held.
         * Must not be called if the surface is not valid.
         * Will unlock the surface when done using it.
         */
        void updatePage(EngineWindowPage currentPage, int pageIndx, int numPages,
                float xOffsetStep) {
                float wallpaperDimAmount) {

            assertBackgroundThread();

            // in case the clock is zero, we start with negative time
            long current = SystemClock.elapsedRealtime() - DEFAULT_UPDATE_SCREENSHOT_DURATION;
            long lapsed = current - currentPage.getLastUpdateTime();
            // Always update the page when the last update time is <= 0
            // This is important especially when the device first boots
            if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) {
                return;
            }
            if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) return;

            Surface surface = mSurfaceHolder.getSurface();
            if (!surface.isValid()) return;
            boolean widthIsLarger = mSurfaceSize.x > mSurfaceSize.y;
@@ -1725,9 +1750,12 @@ public abstract class WallpaperService extends Service {
            Bitmap screenShot = Bitmap.createBitmap(width, height,
                    Bitmap.Config.ARGB_8888);
            final Bitmap finalScreenShot = screenShot;
            Trace.beginSection("WallpaperService#pixelCopy");
            final String pixelCopySectionName = "WallpaperService#pixelCopy";
            final int pixelCopyCount = mPixelCopyCount++;
            Trace.beginAsyncSection(pixelCopySectionName, pixelCopyCount);
            try {
                PixelCopy.request(surface, screenShot, (res) -> {
                Trace.endSection();
                    Trace.endAsyncSection(pixelCopySectionName, pixelCopyCount);
                    if (DEBUG) Log.d(TAG, "result of pixel copy is " + res);
                    if (res != PixelCopy.SUCCESS) {
                        Bitmap lastBitmap = currentPage.getBitmap();
@@ -1736,22 +1764,28 @@ public abstract class WallpaperService extends Service {
                        Bitmap lastScreenshot = mLastScreenshot;
                        if (lastScreenshot != null && !lastScreenshot.isRecycled()
                                && !Objects.equals(lastBitmap, lastScreenshot)) {
                        updatePageColors(currentPage, pageIndx, numPages, xOffsetStep);
                            updatePageColors(currentPage, pageIndx, numPages, wallpaperDimAmount);
                        }
                    } else {
                        mLastScreenshot = finalScreenShot;
                        // going to hold this lock for a while
                        currentPage.setBitmap(finalScreenShot);
                        currentPage.setLastUpdateTime(current);
                    updatePageColors(currentPage, pageIndx, numPages, xOffsetStep);
                        updatePageColors(currentPage, pageIndx, numPages, wallpaperDimAmount);
                    }
                }, mBackgroundHandler);
            } catch (IllegalArgumentException e) {
                // this can potentially happen if the surface is invalidated right between the
                // surface.isValid() check and the PixelCopy operation.
                // in this case, stop: we'll compute colors on the next processLocalColors call.
                Log.i(TAG, "Cancelling processLocalColors: exception caught during PixelCopy");
            }
            }, mHandler);

        }
        // locked by the passed page
        private void updatePageColors(EngineWindowPage page, int pageIndx, int numPages,
                float xOffsetStep) {
        private void updatePageColors(
                EngineWindowPage page, int pageIndx, int numPages, float wallpaperDimAmount) {
            if (page.getBitmap() == null) return;
            assertBackgroundThread();
            Trace.beginSection("WallpaperService#updatePageColors");
            if (DEBUG) {
                Log.d(TAG, "updatePageColorsLocked for page " + pageIndx + " with areas "
@@ -1773,7 +1807,7 @@ public abstract class WallpaperService extends Service {
                    Log.e(TAG, "Error creating page local color bitmap", e);
                    continue;
                }
                WallpaperColors color = WallpaperColors.fromBitmap(target, mWallpaperDimAmount);
                WallpaperColors color = WallpaperColors.fromBitmap(target, wallpaperDimAmount);
                target.recycle();
                WallpaperColors currentColor = page.getColors(area);

@@ -1790,17 +1824,26 @@ public abstract class WallpaperService extends Service {
                                + " local color callback for area" + area + " for page " + pageIndx
                                + " of " + numPages);
                    }
                    mHandler.post(() -> {
                        try {
                            mConnection.onLocalWallpaperColorsChanged(area, color,
                                    mDisplayContext.getDisplayId());
                        } catch (RemoteException e) {
                            Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e);
                        }
                    });
                }
            }
            Trace.endSection();
        }

        private void assertBackgroundThread() {
            if (!mBackgroundHandler.getLooper().isCurrentThread()) {
                throw new IllegalStateException(
                        "ProcessLocalColors should be called from the background thread");
            }
        }

        private RectF generateSubRect(RectF in, int pageInx, int numPages) {
            float minLeft = (float) (pageInx) / (float) (numPages);
            float maxRight = (float) (pageInx + 1) / (float) (numPages);
@@ -1825,7 +1868,6 @@ public abstract class WallpaperService extends Service {
            if (supportsLocalColorExtraction()) return;
            if (!mResetWindowPages) return;
            mResetWindowPages = false;
            mLastWindowPage = -1;
            for (int i = 0; i < mWindowPages.length; i++) {
                mWindowPages[i].setLastUpdateTime(0L);
            }
@@ -1851,12 +1893,10 @@ public abstract class WallpaperService extends Service {
            if (DEBUG) {
                Log.d(TAG, "addLocalColorsAreas adding local color areas " + regions);
            }
            mHandler.post(() -> {
            mBackgroundHandler.post(() -> {
                mLocalColorsToAdd.addAll(regions);
                processLocalColors(mPendingXOffset, mPendingYOffset);
                processLocalColors();
            });


        }

        /**
@@ -1866,7 +1906,7 @@ public abstract class WallpaperService extends Service {
         */
        public void removeLocalColorsAreas(@NonNull List<RectF> regions) {
            if (supportsLocalColorExtraction()) return;
            mHandler.post(() -> {
            mBackgroundHandler.post(() -> {
                float step = mPendingXOffsetStep;
                mLocalColorsToAdd.removeAll(regions);
                mLocalColorAreas.removeAll(regions);
@@ -2497,6 +2537,9 @@ public abstract class WallpaperService extends Service {
    @Override
    public void onCreate() {
        Trace.beginSection("WPMS.onCreate");
        mBackgroundThread = new HandlerThread("DefaultWallpaperLocalColorExtractor");
        mBackgroundThread.start();
        mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
        super.onCreate();
        Trace.endSection();
    }
@@ -2509,6 +2552,7 @@ public abstract class WallpaperService extends Service {
            mActiveEngines.get(i).detach();
        }
        mActiveEngines.clear();
        mBackgroundThread.quitSafely();
        Trace.endSection();
    }

+14 −0
Original line number Diff line number Diff line
@@ -213,6 +213,12 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        final View handle = caption.findViewById(R.id.caption_handle);
        handle.setOnTouchListener(mOnCaptionTouchListener);
        handle.setOnClickListener(mOnCaptionButtonClickListener);
        if (DesktopModeStatus.isProto1Enabled()) {
            final View back = caption.findViewById(R.id.back_button);
            back.setOnClickListener(mOnCaptionButtonClickListener);
            final View close = caption.findViewById(R.id.close_window);
            close.setOnClickListener(mOnCaptionButtonClickListener);
        }
        updateButtonVisibility();
    }

@@ -319,6 +325,14 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        final View handle = caption.findViewById(R.id.caption_handle);
        final Drawable handleBackground = handle.getBackground();
        handleBackground.setTintList(buttonTintColor);
        if (DesktopModeStatus.isProto1Enabled()) {
            final View back = caption.findViewById(R.id.back_button);
            final Drawable backBackground = back.getBackground();
            backBackground.setTintList(buttonTintColor);
            final View close = caption.findViewById(R.id.close_window);
            final Drawable closeBackground = close.getBackground();
            closeBackground.setTintList(buttonTintColor);
        }
    }

    private void closeDragResizeListener() {
+1 −2
Original line number Diff line number Diff line
@@ -35,8 +35,7 @@ interface LaunchableView {
     *
     * Note that calls to [View.setTransitionVisibility] shouldn't be blocked.
     *
     * @param block whether we should block/postpone all calls to `setVisibility` and
     * `setTransitionVisibility`.
     * @param block whether we should block/postpone all calls to `setVisibility`.
     */
    fun setShouldBlockVisibilityChanges(block: Boolean)
}
+1 −1
Original line number Diff line number Diff line
@@ -68,7 +68,7 @@ class RippleAnimation(private val config: RippleAnimationConfig) {
    private fun applyConfigToShader() {
        with(rippleShader) {
            setCenter(config.centerX, config.centerY)
            setMaxSize(config.maxWidth, config.maxHeight)
            rippleSize.setMaxSize(config.maxWidth, config.maxHeight)
            pixelDensity = config.pixelDensity
            color = ColorUtils.setAlphaComponent(config.color, config.opacity)
            sparkleStrength = config.sparkleStrength
+124 −21
Original line number Diff line number Diff line
@@ -15,9 +15,10 @@
 */
package com.android.systemui.surfaceeffects.ripple

import android.graphics.PointF
import android.graphics.RuntimeShader
import android.util.Log
import android.util.MathUtils
import androidx.annotation.VisibleForTesting
import com.android.systemui.animation.Interpolators
import com.android.systemui.surfaceeffects.shaderutil.SdfShaderLibrary
import com.android.systemui.surfaceeffects.shaderutil.ShaderUtilLibrary
@@ -44,6 +45,8 @@ class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) :
    }
    // language=AGSL
    companion object {
        private val TAG = RippleShader::class.simpleName

        // Default fade in/ out values. The value range is [0,1].
        const val DEFAULT_FADE_IN_START = 0f
        const val DEFAULT_FADE_OUT_END = 1f
@@ -99,7 +102,7 @@ class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) :
            vec4 main(vec2 p) {
                float sparkleRing = soften(roundedBoxRing(p-in_center, in_size, in_cornerRadius,
                    in_thickness), in_blur);
                float inside = soften(sdRoundedBox(p-in_center, in_size * 1.2, in_cornerRadius),
                float inside = soften(sdRoundedBox(p-in_center, in_size * 1.25, in_cornerRadius),
                    in_blur);
                float sparkle = sparkles(p - mod(p, in_pixelDensity * 0.8), in_time * 0.00175)
                    * (1.-sparkleRing) * in_fadeSparkle;
@@ -184,12 +187,17 @@ class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) :
        setFloatUniform("in_center", x, y)
    }

    /** Max width of the ripple. */
    private var maxSize: PointF = PointF()
    fun setMaxSize(width: Float, height: Float) {
        maxSize.x = width
        maxSize.y = height
    }
    /**
     * Blur multipliers for the ripple.
     *
     * <p>It interpolates from [blurStart] to [blurEnd] based on the [progress]. Increase number to
     * add more blur.
     */
    var blurStart: Float = 1.25f
    var blurEnd: Float = 0.5f

    /** Size of the ripple. */
    val rippleSize = RippleSize()

    /**
     * Linear progress of the ripple. Float value between [0, 1].
@@ -209,15 +217,19 @@ class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) :
    /** Progress with Standard easing curve applied. */
    private var progress: Float = 0.0f
        set(value) {
            currentWidth = maxSize.x * value
            currentHeight = maxSize.y * value
            setFloatUniform("in_size", currentWidth, currentHeight)
            field = value

            setFloatUniform("in_thickness", maxSize.y * value * 0.5f)
            // radius should not exceed width and height values.
            setFloatUniform("in_cornerRadius", Math.min(maxSize.x, maxSize.y) * value)
            rippleSize.update(value)

            setFloatUniform("in_blur", MathUtils.lerp(1.25f, 0.5f, value))
            setFloatUniform("in_size", rippleSize.currentWidth, rippleSize.currentHeight)
            setFloatUniform("in_thickness", rippleSize.currentHeight * 0.5f)
            // Corner radius is always max of the min between the current width and height.
            setFloatUniform(
                "in_cornerRadius",
                Math.min(rippleSize.currentWidth, rippleSize.currentHeight)
            )

            setFloatUniform("in_blur", MathUtils.lerp(blurStart, blurEnd, value))
        }

    /** Play time since the start of the effect. */
@@ -264,12 +276,6 @@ class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) :
            setFloatUniform("in_pixelDensity", value)
        }

    var currentWidth: Float = 0f
        private set

    var currentHeight: Float = 0f
        private set

    /** Parameters that are used to fade in/ out of the sparkle ring. */
    val sparkleRingFadeParams =
        FadeParams(
@@ -342,4 +348,101 @@ class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) :
        /** The endpoint of the fade out, given that the animation goes from 0 to 1. */
        var fadeOutEnd: Float = DEFAULT_FADE_OUT_END,
    )

    /**
     * Desired size of the ripple at a point t in [progress].
     *
     * <p>Note that [progress] is curved and normalized. Below is an example usage:
     * SizeAtProgress(t= 0f, width= 0f, height= 0f), SizeAtProgress(t= 0.2f, width= 500f, height=
     * 700f), SizeAtProgress(t= 1f, width= 100f, height= 300f)
     *
     * <p>For simple ripple effects, you will want to use [setMaxSize] as it is translated into:
     * SizeAtProgress(t= 0f, width= 0f, height= 0f), SizeAtProgress(t= 1f, width= maxWidth, height=
     * maxHeight)
     */
    data class SizeAtProgress(
        /** Time t in [0,1] progress range. */
        var t: Float,
        /** Target width size of the ripple at time [t]. */
        var width: Float,
        /** Target height size of the ripple at time [t]. */
        var height: Float
    )

    /** Updates and stores the ripple size. */
    inner class RippleSize {
        @VisibleForTesting var sizes = mutableListOf<SizeAtProgress>()
        @VisibleForTesting var currentSizeIndex = 0
        @VisibleForTesting val initialSize = SizeAtProgress(0f, 0f, 0f)

        var currentWidth: Float = 0f
            private set
        var currentHeight: Float = 0f
            private set

        /**
         * Sets the max size of the ripple.
         *
         * <p>Use this if the ripple shape simply changes linearly.
         */
        fun setMaxSize(width: Float, height: Float) {
            setSizeAtProgresses(initialSize, SizeAtProgress(1f, width, height))
        }

        /**
         * Sets the list of [sizes].
         *
         * <p>Note that setting this clears the existing sizes.
         */
        fun setSizeAtProgresses(vararg sizes: SizeAtProgress) {
            // Reset everything.
            this.sizes.clear()
            currentSizeIndex = 0

            this.sizes.addAll(sizes)
            this.sizes.sortBy { it.t }
        }

        /**
         * Updates the current ripple size based on the progress.
         *
         * <p>Should be called when progress updates.
         */
        fun update(progress: Float) {
            val targetIndex = updateTargetIndex(progress)
            val prevIndex = Math.max(targetIndex - 1, 0)

            val targetSize = sizes[targetIndex]
            val prevSize = sizes[prevIndex]

            val subProgress = subProgress(prevSize.t, targetSize.t, progress)

            currentWidth = targetSize.width * subProgress + prevSize.width
            currentHeight = targetSize.height * subProgress + prevSize.height
        }

        private fun updateTargetIndex(progress: Float): Int {
            if (sizes.isEmpty()) {
                // It could be empty on init.
                if (progress > 0f) {
                    Log.e(
                        TAG,
                        "Did you forget to set the ripple size? Use [setMaxSize] or " +
                            "[setSizeAtProgresses] before playing the animation."
                    )
                }
                // If there's no size is set, we set everything to 0.
                setSizeAtProgresses(initialSize)
            }

            var candidate = sizes[currentSizeIndex]

            while (progress > candidate.t) {
                currentSizeIndex = Math.min(currentSizeIndex + 1, sizes.size - 1)
                candidate = sizes[currentSizeIndex]
            }

            return currentSizeIndex
        }
    }
}
Loading