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

Commit 75ec3790 authored by Lucas Dupin's avatar Lucas Dupin
Browse files

WallpaperColors caching and synchronization

Making sure that colors are being cached in
WallpaperManagerService and that sysui won't
force a new color extraction.

Fixes: 62958267
Test: manual, reboot, look at systrace
Test: runtest -x cts/tests/app/src/android/app/cts/WallpaperManagerTest.java
Change-Id: Ic079a8e3d4d4ad65947b718dcc544f795c16f152
parent 5c5f1f64
Loading
Loading
Loading
Loading
+38 −6
Original line number Diff line number Diff line
@@ -16,12 +16,14 @@

package com.google.android.colorextraction;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WallpaperColors;
import android.app.WallpaperManager;
import android.content.Context;
import android.support.annotation.NonNull;
import android.os.AsyncTask;
import android.os.Trace;
import android.support.annotation.VisibleForTesting;
import android.support.v4.graphics.ColorUtils;
import android.util.Log;
import android.util.SparseArray;

@@ -29,6 +31,7 @@ import com.google.android.colorextraction.types.ExtractionType;
import com.google.android.colorextraction.types.Tonal;

import java.util.ArrayList;
import java.util.List;

/**
 * Class to process wallpaper colors and generate a tonal palette based on them.
@@ -50,6 +53,8 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener
    private final ArrayList<OnColorsChangedListener> mOnColorsChangedListeners;
    private final Context mContext;
    private final ExtractionType mExtractionType;
    private WallpaperColors mSystemColors;
    private WallpaperColors mLockColors;

    public ColorExtractor(Context context) {
        this(context, new Tonal());
@@ -70,7 +75,6 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener
        }

        mOnColorsChangedListeners = new ArrayList<>();

        WallpaperManager wallpaperManager = mContext.getSystemService(WallpaperManager.class);
        if (wallpaperManager == null) {
            Log.w(TAG, "Can't listen to color changes!");
@@ -78,17 +82,25 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener
            wallpaperManager.addOnColorsChangedListener(this);

            // Initialize all gradients with the current colors
            GradientColors[] systemColors = mGradientColors.get(WallpaperManager.FLAG_SYSTEM);
            extractInto(wallpaperManager.getWallpaperColors(WallpaperManager.FLAG_SYSTEM),
            Trace.beginSection("ColorExtractor#getWallpaperColors");
            mSystemColors = wallpaperManager.getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
            mLockColors = wallpaperManager.getWallpaperColors(WallpaperManager.FLAG_LOCK);

            GradientColors[] systemColors = mGradientColors.get(
                    WallpaperManager.FLAG_SYSTEM);
            extractInto(mSystemColors,
                    systemColors[TYPE_NORMAL],
                    systemColors[TYPE_DARK],
                    systemColors[TYPE_EXTRA_DARK]);

            GradientColors[] lockColors = mGradientColors.get(WallpaperManager.FLAG_LOCK);
            extractInto(wallpaperManager.getWallpaperColors(WallpaperManager.FLAG_LOCK),
            extractInto(mLockColors,
                    lockColors[TYPE_NORMAL],
                    lockColors[TYPE_DARK],
                    lockColors[TYPE_EXTRA_DARK]);
            triggerColorsChanged(WallpaperManager.FLAG_SYSTEM
                    | WallpaperManager.FLAG_LOCK);
            Trace.endSection();
        }
    }

@@ -110,6 +122,7 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener
     * @param type TYPE_NORMAL, TYPE_DARK or TYPE_EXTRA_DARK
     * @return colors
     */
    @NonNull
    public GradientColors getColors(int which, int type) {
        if (type != TYPE_NORMAL && type != TYPE_DARK && type != TYPE_EXTRA_DARK) {
            throw new IllegalArgumentException(
@@ -121,16 +134,35 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener
        return mGradientColors.get(which)[type];
    }

    /**
     * Get the last available WallpaperColors without forcing new extraction.
     *
     * @param which FLAG_LOCK or FLAG_SYSTEM
     * @return Last cached colors
     */
    @Nullable
    public WallpaperColors getWallpaperColors(int which) {
        if (which == WallpaperManager.FLAG_LOCK) {
            return mLockColors;
        } else if (which == WallpaperManager.FLAG_SYSTEM) {
            return mSystemColors;
        } else {
            throw new IllegalArgumentException("Invalid value for which: " + which);
        }
    }

    @Override
    public void onColorsChanged(WallpaperColors colors, int which) {
        boolean changed = false;
        if ((which & WallpaperManager.FLAG_LOCK) != 0) {
            mLockColors = colors;
            GradientColors[] lockColors = mGradientColors.get(WallpaperManager.FLAG_LOCK);
            extractInto(colors, lockColors[TYPE_NORMAL], lockColors[TYPE_DARK],
                    lockColors[TYPE_EXTRA_DARK]);
            changed = true;
        }
        if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
            mSystemColors = colors;
            GradientColors[] systemColors = mGradientColors.get(WallpaperManager.FLAG_SYSTEM);
            extractInto(colors, systemColors[TYPE_NORMAL], systemColors[TYPE_DARK],
                    systemColors[TYPE_EXTRA_DARK]);
+3 −0
Original line number Diff line number Diff line
@@ -268,6 +268,9 @@ public class Dependency extends SystemUI {
        mProviders.put(AccessibilityManagerWrapper.class,
                () -> new AccessibilityManagerWrapper(mContext));

        // Creating a new instance will trigger color extraction.
        // Thankfully this only happens once - during boot - and WallpaperManagerService
        // loads colors from cache.
        mProviders.put(SysuiColorExtractor.class, () -> new SysuiColorExtractor(mContext));

        mProviders.put(TunablePaddingService.class, () -> new TunablePaddingService());
+2 −2
Original line number Diff line number Diff line
@@ -304,8 +304,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
            mNeedsDrawableColorUpdate = false;
            if (mKeyguardShowing) {
                // Always animate color changes if we're seeing the keyguard
                mScrimInFront.setColors(mLockColors);
                mScrimBehind.setColors(mLockColors);
                mScrimInFront.setColors(mLockColors, true /* animated */);
                mScrimBehind.setColors(mLockColors, true /* animated */);
            } else {
                // Only animate scrim color if the scrim view is actually visible
                boolean animateScrimInFront = mScrimInFront.getViewAlpha() != 0;
+7 −10
Original line number Diff line number Diff line
@@ -4559,17 +4559,14 @@ public class StatusBar extends SystemUI implements DemoMode,
                .supportsDarkText();
        // And wallpaper defines if QS should be light or dark.
        boolean useDarkTheme = false;
        final WallpaperManager wallpaperManager = mContext.getSystemService(WallpaperManager.class);
        if (wallpaperManager != null) {
            WallpaperColors wallpaperColors = wallpaperManager
                    .getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
            if (wallpaperColors != null) {
                final int mainColor = wallpaperColors.getPrimaryColor().toArgb();
                final float[] hsl = new float[3];
        final WallpaperColors systemColors =
                mColorExtractor.getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
        if (systemColors != null) {
            int mainColor = systemColors.getPrimaryColor().toArgb();
            float[] hsl = new float[3];
            ColorUtils.colorToHSL(mainColor, hsl);
            useDarkTheme = hsl[2] < 0.2f;
        }
        }

        // Enable/disable dark UI.
        if (isUsingDarkTheme() != useDarkTheme) {
+38 −26
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.app.IWallpaperManager;
import android.app.IWallpaperManagerCallback;
import android.app.PendingIntent;
import android.app.UserSwitchObserver;
import android.app.WallpaperColors;
import android.app.WallpaperInfo;
import android.app.WallpaperManager;
import android.app.admin.DevicePolicyManager;
@@ -55,7 +56,6 @@ import android.graphics.BitmapRegionDecoder;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
@@ -64,8 +64,8 @@ import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.Process;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SELinux;
@@ -76,12 +76,10 @@ import android.os.UserManager;
import android.service.wallpaper.IWallpaperConnection;
import android.service.wallpaper.IWallpaperEngine;
import android.service.wallpaper.IWallpaperService;
import android.app.WallpaperColors;
import android.service.wallpaper.WallpaperService;
import android.system.ErrnoException;
import android.system.Os;
import android.util.EventLog;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
@@ -99,7 +97,6 @@ import com.android.server.EventLogTags;
import com.android.server.FgThread;
import com.android.server.SystemService;

import java.util.ArrayList;
import libcore.io.IoUtils;

import org.xmlpull.v1.XmlPullParser;
@@ -347,35 +344,47 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
            needsExtraction = wallpaper.primaryColors == null;
        }

        // This should not be synchronized because color extraction
        // might take a while.
        // Let's notify the current values, it's fine if it's null, it just means
        // that we don't know yet.
        notifyColorListeners(wallpaper.primaryColors, which);

        if (needsExtraction) {
            extractColors(wallpaper);
            notifyColorListeners(wallpaper.primaryColors, which);
        }
    }

    private void notifyColorListeners(WallpaperColors wallpaperColors, int which) {
        final IWallpaperManagerCallback[] listeners;
        final IWallpaperManagerCallback keyguardListener;
        synchronized (mLock) {
            final int n = mColorsChangedListeners.beginBroadcast();
            for (int i = 0; i < n; i++) {
                IWallpaperManagerCallback callback = mColorsChangedListeners.getBroadcastItem(i);
            // Make a synchronized copy of the listeners to avoid concurrent list modification.
            int callbackCount = mColorsChangedListeners.beginBroadcast();
            listeners = new IWallpaperManagerCallback[callbackCount];
            for (int i = 0; i < callbackCount; i++) {
                listeners[i] = mColorsChangedListeners.getBroadcastItem(i);
            }
            mColorsChangedListeners.finishBroadcast();
            keyguardListener = mKeyguardListener;
        }

        for (int i = 0; i < listeners.length; i++) {
            try {
                    callback.onWallpaperColorsChanged(wallpaper.primaryColors, which);
                listeners[i].onWallpaperColorsChanged(wallpaperColors, which);
            } catch (RemoteException e) {
                // Callback is gone, it's not necessary to unregister it since
                // RemoteCallbackList#getBroadcastItem will take care of it.
            }
        }
            mColorsChangedListeners.finishBroadcast();

            final IWallpaperManagerCallback cb = mKeyguardListener;
            if (cb != null) {
        if (keyguardListener != null) {
            try {
                    cb.onWallpaperColorsChanged(wallpaper.primaryColors, which);
                keyguardListener.onWallpaperColorsChanged(wallpaperColors, which);
            } catch (RemoteException e) {
                // Oh well it went away; no big deal
            }
        }
    }
    }

    /**
     * We can easily extract colors from an ImageWallpaper since it's only a bitmap.
@@ -414,6 +423,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
        synchronized (mLock) {
            if (wallpaper.wallpaperId == wallpaperId) {
                wallpaper.primaryColors = colors;
                // Now that we have the colors, let's save them into the xml
                // to avoid having to run this again.
                saveSettingsLocked(wallpaper.userId);
            } else {
                Slog.w(TAG, "Not setting primary colors since wallpaper changed");
            }
@@ -1366,6 +1378,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {

            RuntimeException e = null;
            try {
                wallpaper.primaryColors = null;
                wallpaper.imageWallpaperPending = false;
                if (userId != mCurrentUserId) return;
                if (bindWallpaperComponentLocked(defaultFailed
@@ -1843,6 +1856,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
            try {
                wallpaper.imageWallpaperPending = false;
                if (bindWallpaperComponentLocked(name, false, true, wallpaper, null)) {
                    wallpaper.primaryColors = null;
                    wallpaper.wallpaperId = makeWallpaperIdLocked();
                    notifyCallbacksLocked(wallpaper);
                    shouldNotifyColors = true;
@@ -1979,7 +1993,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
            }
            wallpaper.wallpaperComponent = componentName;
            wallpaper.connection = newConn;
            wallpaper.primaryColors = null;
            newConn.mReply = reply;
            try {
                if (wallpaper.userId == mCurrentUserId) {
@@ -2185,7 +2198,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
                    out.attribute(null, "colorValue"+i, Integer.toString(wc.toArgb()));
                }
            }
            out.attribute(null, "supportsDarkText",
            out.attribute(null, "colorHints",
                    Integer.toString(wallpaper.primaryColors.getColorHints()));
        }

@@ -2422,7 +2435,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
        int colorsCount = getAttributeInt(parser, "colorsCount", 0);
        if (colorsCount > 0) {
            Color primary = null, secondary = null, tertiary = null;
            final List<Color> colors = new ArrayList<>();
            for (int i = 0; i < colorsCount; i++) {
                Color color = Color.valueOf(getAttributeInt(parser, "colorValue" + i, 0));
                if (i == 0) {