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

Commit 869e636a authored by Aurélien Pomini's avatar Aurélien Pomini Committed by Android (Google) Code Review
Browse files

Merge "Move color extraction to ImageWallpaper" into main

parents 6cdbe0f2 f0f455f9
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -27,12 +27,15 @@ import static android.graphics.Matrix.MSKEW_Y;
import static android.view.View.SYSTEM_UI_FLAG_VISIBLE;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;

import static com.android.window.flags.Flags.FLAG_OFFLOAD_COLOR_EXTRACTION;
import static com.android.window.flags.Flags.noConsecutiveVisibilityEvents;
import static com.android.window.flags.Flags.offloadColorExtraction;

import android.animation.AnimationHandler;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.FlaggedApi;
import android.annotation.FloatRange;
import android.annotation.MainThread;
import android.annotation.NonNull;
@@ -831,6 +834,15 @@ public abstract class WallpaperService extends Service {
        public void onAmbientModeChanged(boolean inAmbientMode, long animationDuration) {
        }

        /**
         * Called when the dim amount of the wallpaper changed. This can be used to recompute the
         * wallpaper colors based on the new dim, and call {@link #notifyColorsChanged()}.
         * @hide
         */
        @FlaggedApi(FLAG_OFFLOAD_COLOR_EXTRACTION)
        public void onDimAmountChanged(float dimAmount) {
        }

        /**
         * Called when an application has changed the desired virtual size of
         * the wallpaper.
@@ -1043,6 +1055,10 @@ public abstract class WallpaperService extends Service {
            }

            mPreviousWallpaperDimAmount = mWallpaperDimAmount;

            // after the dim changes, allow colors to be immediately recomputed
            mLastColorInvalidation = 0;
            if (offloadColorExtraction()) onDimAmountChanged(mWallpaperDimAmount);
        }

        /**
+10 −0
Original line number Diff line number Diff line
@@ -22,3 +22,13 @@ flag {
  description: "Prevent the system from sending consecutive onVisibilityChanged(false) events."
  bug: "285631818"
}

flag {
  name: "offload_color_extraction"
  namespace: "systemui"
  description: "Let ImageWallpaper take care of its wallpaper color extraction, instead of system_server"
  bug: "328791519"
  metadata {
    purpose: PURPOSE_BUGFIX
  }
}
 No newline at end of file
+21 −0
Original line number Diff line number Diff line
@@ -20,6 +20,9 @@ import static android.app.WallpaperManager.FLAG_LOCK;
import static android.app.WallpaperManager.FLAG_SYSTEM;
import static android.app.WallpaperManager.SetWallpaperFlags;

import static com.android.window.flags.Flags.offloadColorExtraction;

import android.annotation.Nullable;
import android.app.WallpaperColors;
import android.app.WallpaperManager;
import android.content.Context;
@@ -135,6 +138,12 @@ public class ImageWallpaper extends WallpaperService {
                    mLongExecutor,
                    mLock,
                    new WallpaperLocalColorExtractor.WallpaperLocalColorExtractorCallback() {

                        @Override
                        public void onColorsProcessed() {
                            CanvasEngine.this.notifyColorsChanged();
                        }

                        @Override
                        public void onColorsProcessed(List<RectF> regions,
                                List<WallpaperColors> colors) {
@@ -432,6 +441,12 @@ public class ImageWallpaper extends WallpaperService {
            unloadBitmapIfNotUsed();
        }

        @Override
        public @Nullable WallpaperColors onComputeColors() {
            if (!offloadColorExtraction()) return null;
            return mWallpaperLocalColorExtractor.onComputeColors();
        }

        @Override
        public boolean supportsLocalColorExtraction() {
            return true;
@@ -468,6 +483,12 @@ public class ImageWallpaper extends WallpaperService {
            }
        }

        @Override
        public void onDimAmountChanged(float dimAmount) {
            if (!offloadColorExtraction()) return;
            mWallpaperLocalColorExtractor.onDimAmountChanged(dimAmount);
        }

        @Override
        public void onDisplayAdded(int displayId) {

+73 −8
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@

package com.android.systemui.wallpapers;

import static com.android.window.flags.Flags.offloadColorExtraction;

import android.app.WallpaperColors;
import android.graphics.Bitmap;
import android.graphics.Rect;
@@ -66,6 +68,12 @@ public class WallpaperLocalColorExtractor {
    private final List<RectF> mPendingRegions = new ArrayList<>();
    private final Set<RectF> mProcessedRegions = new ArraySet<>();

    private float mWallpaperDimAmount = 0f;
    private WallpaperColors mWallpaperColors;

    // By default we assume that colors were loaded from disk and don't need to be recomputed
    private boolean mRecomputeColors = false;

    @LongRunning
    private final Executor mLongExecutor;

@@ -75,6 +83,12 @@ public class WallpaperLocalColorExtractor {
     * Interface to handle the callbacks after the different steps of the color extraction
     */
    public interface WallpaperLocalColorExtractorCallback {

        /**
         * Callback after the wallpaper colors have been computed
         */
        void onColorsProcessed();

        /**
         * Callback after the colors of new regions have been extracted
         * @param regions the list of new regions that have been processed
@@ -129,7 +143,7 @@ public class WallpaperLocalColorExtractor {
            if (displayWidth == mDisplayWidth && displayHeight == mDisplayHeight) return;
            mDisplayWidth = displayWidth;
            mDisplayHeight = displayHeight;
            processColorsInternal();
            processLocalColorsInternal();
        }
    }

@@ -166,7 +180,8 @@ public class WallpaperLocalColorExtractor {
            mBitmapHeight = bitmap.getHeight();
            mMiniBitmap = createMiniBitmap(bitmap);
            mWallpaperLocalColorExtractorCallback.onMiniBitmapUpdated();
            recomputeColors();
            if (offloadColorExtraction() && mRecomputeColors) recomputeColorsInternal();
            recomputeLocalColors();
        }
    }

@@ -184,16 +199,66 @@ public class WallpaperLocalColorExtractor {
            if (mPages == pages) return;
            mPages = pages;
            if (mMiniBitmap != null && !mMiniBitmap.isRecycled()) {
                recomputeColors();
                recomputeLocalColors();
            }
        }
    }

    /**
     * Should be called when the dim amount of the wallpaper changes, to recompute the colors
     */
    public void onDimAmountChanged(float dimAmount) {
        mLongExecutor.execute(() -> onDimAmountChangedSynchronized(dimAmount));
    }

    private void onDimAmountChangedSynchronized(float dimAmount) {
        synchronized (mLock) {
            if (mWallpaperDimAmount == dimAmount) return;
            mWallpaperDimAmount = dimAmount;
            mRecomputeColors = true;
            recomputeColorsInternal();
        }
    }

    /**
     * To be called by {@link ImageWallpaper.CanvasEngine#onComputeColors}. This will either
     * return the current wallpaper colors, or if the bitmap is not yet loaded, return null and call
     * {@link WallpaperLocalColorExtractorCallback#onColorsProcessed()} when the colors are ready.
     */
    public WallpaperColors onComputeColors() {
        mLongExecutor.execute(this::onComputeColorsSynchronized);
        return mWallpaperColors;
    }

    private void onComputeColorsSynchronized() {
        synchronized (mLock) {
            if (mRecomputeColors) return;
            mRecomputeColors = true;
            recomputeColorsInternal();
        }
    }

    /**
     * helper to recompute main colors, to be called in synchronized methods
     */
    private void recomputeColorsInternal() {
        if (mMiniBitmap == null) return;
        mWallpaperColors = getWallpaperColors(mMiniBitmap, mWallpaperDimAmount);
        mWallpaperLocalColorExtractorCallback.onColorsProcessed();
    }

    @VisibleForTesting
    WallpaperColors getWallpaperColors(@NonNull Bitmap bitmap, float dimAmount) {
        return WallpaperColors.fromBitmap(bitmap, dimAmount);
    }

    // helper to recompute colors, to be called in synchronized methods
    private void recomputeColors() {
    /**
     * helper to recompute local colors, to be called in synchronized methods
     */
    private void recomputeLocalColors() {
        mPendingRegions.addAll(mProcessedRegions);
        mProcessedRegions.clear();
        processColorsInternal();
        processLocalColorsInternal();
    }

    /**
@@ -216,7 +281,7 @@ public class WallpaperLocalColorExtractor {
            if (!wasActive && isActive()) {
                mWallpaperLocalColorExtractorCallback.onActivated();
            }
            processColorsInternal();
            processLocalColorsInternal();
        }
    }

@@ -353,7 +418,7 @@ public class WallpaperLocalColorExtractor {
     * then notify the callback with the resulting colors for these regions
     * This method should only be called synchronously
     */
    private void processColorsInternal() {
    private void processLocalColorsInternal() {
        /*
         * if the miniBitmap is not yet loaded, that means the onBitmapChanged has not yet been
         * called, and thus the wallpaper is not yet loaded. In that case, exit, the function
+75 −6
Original line number Diff line number Diff line
@@ -16,9 +16,12 @@

package com.android.systemui.wallpapers;

import static com.android.window.flags.Flags.FLAG_OFFLOAD_COLOR_EXTRACTION;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
@@ -32,6 +35,7 @@ import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.RectF;
import android.platform.test.annotations.EnableFlags;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;

@@ -77,6 +81,7 @@ public class WallpaperLocalColorExtractorTest extends SysuiTestCase {
    private Executor mBackgroundExecutor;

    private int mColorsProcessed;
    private int mLocalColorsProcessed;
    private int mMiniBitmapUpdatedCount;
    private int mActivatedCount;
    private int mDeactivatedCount;
@@ -93,6 +98,7 @@ public class WallpaperLocalColorExtractorTest extends SysuiTestCase {

    private void resetCounters() {
        mColorsProcessed = 0;
        mLocalColorsProcessed = 0;
        mMiniBitmapUpdatedCount = 0;
        mActivatedCount = 0;
        mDeactivatedCount = 0;
@@ -111,11 +117,15 @@ public class WallpaperLocalColorExtractorTest extends SysuiTestCase {
                mBackgroundExecutor,
                new Object(),
                new WallpaperLocalColorExtractor.WallpaperLocalColorExtractorCallback() {
                    @Override
                    public void onColorsProcessed() {
                        mColorsProcessed++;
                    }
                    @Override
                    public void onColorsProcessed(List<RectF> regions,
                            List<WallpaperColors> colors) {
                        assertThat(regions.size()).isEqualTo(colors.size());
                        mColorsProcessed += regions.size();
                        mLocalColorsProcessed += regions.size();
                    }

                    @Override
@@ -148,8 +158,10 @@ public class WallpaperLocalColorExtractorTest extends SysuiTestCase {
                .when(spyColorExtractor)
                .createMiniBitmap(any(Bitmap.class), anyInt(), anyInt());

        doReturn(new WallpaperColors(Color.valueOf(0), Color.valueOf(0), Color.valueOf(0)))
                .when(spyColorExtractor).getLocalWallpaperColors(any(Rect.class));
        WallpaperColors colors = new WallpaperColors(
                Color.valueOf(0), Color.valueOf(0), Color.valueOf(0));
        doReturn(colors).when(spyColorExtractor).getLocalWallpaperColors(any(Rect.class));
        doReturn(colors).when(spyColorExtractor).getWallpaperColors(any(Bitmap.class), anyFloat());

        return spyColorExtractor;
    }
@@ -244,7 +256,7 @@ public class WallpaperLocalColorExtractorTest extends SysuiTestCase {

            assertThat(mActivatedCount).isEqualTo(1);
            assertThat(mMiniBitmapUpdatedCount).isEqualTo(1);
            assertThat(mColorsProcessed).isEqualTo(regions.size());
            assertThat(mLocalColorsProcessed).isEqualTo(regions.size());

            spyColorExtractor.removeLocalColorAreas(regions);
            assertThat(mDeactivatedCount).isEqualTo(1);
@@ -329,12 +341,69 @@ public class WallpaperLocalColorExtractorTest extends SysuiTestCase {
                spyColorExtractor.onBitmapChanged(newBitmap);
                assertThat(mMiniBitmapUpdatedCount).isEqualTo(1);
            }
            assertThat(mColorsProcessed).isEqualTo(regions.size());
            assertThat(mLocalColorsProcessed).isEqualTo(regions.size());
        }
        spyColorExtractor.removeLocalColorAreas(regions);
        assertThat(mDeactivatedCount).isEqualTo(1);
    }

    /**
     * Test that after the bitmap changes, the colors are computed only if asked via onComputeColors
     */
    @Test
    @EnableFlags(FLAG_OFFLOAD_COLOR_EXTRACTION)
    public void testRecomputeColors() {
        resetCounters();
        Bitmap bitmap = getMockBitmap(HIGH_BMP_WIDTH, HIGH_BMP_HEIGHT);
        WallpaperLocalColorExtractor spyColorExtractor = getSpyWallpaperLocalColorExtractor();
        spyColorExtractor.onBitmapChanged(bitmap);
        assertThat(mColorsProcessed).isEqualTo(0);
        spyColorExtractor.onComputeColors();
        assertThat(mColorsProcessed).isEqualTo(1);
    }

    /**
     * Test that after onComputeColors is called, the colors are computed once the bitmap is loaded
     */
    @Test
    @EnableFlags(FLAG_OFFLOAD_COLOR_EXTRACTION)
    public void testRecomputeColorsBeforeBitmapLoaded() {
        resetCounters();
        Bitmap bitmap = getMockBitmap(HIGH_BMP_WIDTH, HIGH_BMP_HEIGHT);
        WallpaperLocalColorExtractor spyColorExtractor = getSpyWallpaperLocalColorExtractor();
        spyColorExtractor.onComputeColors();
        spyColorExtractor.onBitmapChanged(bitmap);
        assertThat(mColorsProcessed).isEqualTo(1);
    }

    /**
     * Test that after the dim changes, the colors are computed if the bitmap is already loaded
     */
    @Test
    @EnableFlags(FLAG_OFFLOAD_COLOR_EXTRACTION)
    public void testRecomputeColorsOnDimChanged() {
        resetCounters();
        Bitmap bitmap = getMockBitmap(HIGH_BMP_WIDTH, HIGH_BMP_HEIGHT);
        WallpaperLocalColorExtractor spyColorExtractor = getSpyWallpaperLocalColorExtractor();
        spyColorExtractor.onBitmapChanged(bitmap);
        spyColorExtractor.onDimAmountChanged(0.5f);
        assertThat(mColorsProcessed).isEqualTo(1);
    }

    /**
     * Test that after the dim changes, the colors will be recomputed once the bitmap is loaded
     */
    @Test
    @EnableFlags(FLAG_OFFLOAD_COLOR_EXTRACTION)
    public void testRecomputeColorsOnDimChangedBeforeBitmapLoaded() {
        resetCounters();
        Bitmap bitmap = getMockBitmap(HIGH_BMP_WIDTH, HIGH_BMP_HEIGHT);
        WallpaperLocalColorExtractor spyColorExtractor = getSpyWallpaperLocalColorExtractor();
        spyColorExtractor.onDimAmountChanged(0.3f);
        spyColorExtractor.onBitmapChanged(bitmap);
        assertThat(mColorsProcessed).isEqualTo(1);
    }

    @Test
    public void testCleanUp() {
        resetCounters();
@@ -346,6 +415,6 @@ public class WallpaperLocalColorExtractorTest extends SysuiTestCase {
        assertThat(mMiniBitmapUpdatedCount).isEqualTo(1);
        spyColorExtractor.cleanUp();
        spyColorExtractor.addLocalColorsAreas(listOfRandomAreas(MIN_AREAS, MAX_AREAS));
        assertThat(mColorsProcessed).isEqualTo(0);
        assertThat(mLocalColorsProcessed).isEqualTo(0);
    }
}
Loading