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

Commit 97985d84 authored by Lucas Dupin's avatar Lucas Dupin Committed by Android (Google) Code Review
Browse files

Merge "Wallpaper color extraction"

parents f2af2ad0 ea1fb1e0
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.os.ParcelFileDescriptor;
import android.app.IWallpaperManagerCallback;
import android.app.WallpaperInfo;
import android.content.ComponentName;
import android.app.WallpaperColors;

/** @hide */
interface IWallpaperManager {
@@ -135,4 +136,23 @@ interface IWallpaperManager {
     * wallpaper content has changed.
     */
    boolean setLockWallpaperCallback(IWallpaperManagerCallback cb);

    /**
     * Returns the colors used by the lock screen or system wallpaper.
     *
     * @param which either {@link WallpaperManager#FLAG_LOCK}
     * or {@link WallpaperManager#FLAG_SYSTEM}
     * @return colors of chosen wallpaper
     */
    WallpaperColors getWallpaperColors(int which);

    /**
     * Register a callback to receive color updates
     */
    void registerWallpaperColorsCallback(IWallpaperManagerCallback cb);

    /**
     * Unregister a callback that was receiving color updates
     */
    void unregisterWallpaperColorsCallback(IWallpaperManagerCallback cb);
}
+8 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package android.app;

import android.app.WallpaperColors;

/**
 * Callback interface used by IWallpaperManager to send asynchronous 
 * notifications back to its clients.  Note that this is a
@@ -28,4 +30,10 @@ oneway interface IWallpaperManagerCallback {
     * Called when the wallpaper has changed
     */
    void onWallpaperChanged();

    /**
     * Called when wallpaper colors change
     */
    void onWallpaperColorsChanged(in WallpaperColors colors, int which);

}
+19 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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 android.app;

parcelable WallpaperColors;
 No newline at end of file
+60 −2
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.os.Parcelable;

import android.util.Pair;

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

/**
@@ -29,7 +30,19 @@ import java.util.List;
 */
public final class WallpaperColors implements Parcelable {

    private static final float BRIGHT_LUMINANCE = 0.9f;
    private final List<Pair<Color, Integer>> mColors;
    private final boolean mSupportsDarkText;

    public WallpaperColors(Parcel parcel) {
        mColors = new ArrayList<>();
        int count = parcel.readInt();
        for (int i=0; i < count; i++) {
            Color color = Color.valueOf(parcel.readInt());
            int weight = parcel.readInt();
            mColors.add(new Pair<>(color, weight));
        }
        mSupportsDarkText = parcel.readBoolean();
    }

    /**
@@ -43,6 +56,7 @@ public final class WallpaperColors implements Parcelable {
     *               and number of occurrences/influence.
     */
    public WallpaperColors(List<Pair<Color, Integer>> colors) {
        this(colors, calculateDarkTextSupport(colors));
    }

    /**
@@ -55,6 +69,10 @@ public final class WallpaperColors implements Parcelable {
     * @param supportsDarkText can have dark text on top or not
     */
    public WallpaperColors(List<Pair<Color, Integer>> colors, boolean supportsDarkText) {
        if (colors == null)
            colors = new ArrayList<>();
        mColors = colors;
        mSupportsDarkText = supportsDarkText;
    }

    public static final Creator<WallpaperColors> CREATOR = new Creator<WallpaperColors>() {
@@ -76,6 +94,13 @@ public final class WallpaperColors implements Parcelable {

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        int count = mColors.size();
        dest.writeInt(count);
        for (Pair<Color, Integer> color : mColors) {
            dest.writeInt(color.first.toArgb());
            dest.writeInt(color.second);
        }
        dest.writeBoolean(mSupportsDarkText);
    }

    /**
@@ -83,7 +108,22 @@ public final class WallpaperColors implements Parcelable {
     * @return list of colors paired with their weights.
     */
    public List<Pair<Color, Integer>> getColors() {
        return null;
        return mColors;
    }

    @Override
    public boolean equals(Object o) {
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        WallpaperColors other = (WallpaperColors) o;
        return mColors.equals(other.mColors) && mSupportsDarkText == other.mSupportsDarkText;
    }

    @Override
    public int hashCode() {
        return 31 * mColors.hashCode() + (mSupportsDarkText ? 1 : 0);
    }

    /**
@@ -92,6 +132,24 @@ public final class WallpaperColors implements Parcelable {
     * @return true if dark text is supported
     */
    public boolean supportsDarkText() {
        return mSupportsDarkText;
    }

    private static boolean calculateDarkTextSupport(List<Pair<Color, Integer>> colors) {
        if (colors == null) {
            return false;
        }

        Pair<Color, Integer> mainColor = null;

        for (Pair<Color, Integer> color : colors) {
            if (mainColor == null) {
                mainColor = color;
            } else if (color.second > mainColor.second) {
                mainColor = color;
            }
        }
        return mainColor != null &&
                mainColor.first.luminance() > BRIGHT_LUMINANCE;
    }
}
+103 −6
Original line number Diff line number Diff line
@@ -52,13 +52,13 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.view.WindowManagerGlobal;

import libcore.io.IoUtils;
@@ -71,6 +71,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -271,15 +273,20 @@ public class WallpaperManager {
        }
    }

    static class Globals extends IWallpaperManagerCallback.Stub {
    private static class Globals extends IWallpaperManagerCallback.Stub {
        private final IWallpaperManager mService;
        private boolean mColorCallbackRegistered;
        private final ArrayList<Pair<OnColorsChangedListener, Handler>> mColorListeners =
                new ArrayList<>();
        private Bitmap mCachedWallpaper;
        private int mCachedWallpaperUserId;
        private Bitmap mDefaultWallpaper;
        private Handler mMainLooperHandler;

        Globals(Looper looper) {
            IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE);
            mService = IWallpaperManager.Stub.asInterface(b);
            mMainLooperHandler = new Handler(looper);
            forgetLoadedWallpaper();
        }

@@ -292,6 +299,88 @@ public class WallpaperManager {
            forgetLoadedWallpaper();
        }

        /**
         * Start listening to wallpaper color events.
         * Will be called whenever someone changes their wallpaper or if a live wallpaper
         * changes its colors.
         * @param callback Listener
         * @param handler Thread to call it from. Main thread if null.
         */
        public void addOnColorsChangedListener(@NonNull OnColorsChangedListener callback,
                @Nullable Handler handler) {
            synchronized (this) {
                if (!mColorCallbackRegistered) {
                    try {
                        mService.registerWallpaperColorsCallback(this);
                        mColorCallbackRegistered = true;
                    } catch (RemoteException e) {
                        // Failed, service is gone
                        Log.w(TAG, "Can't register for color updates", e);
                    }
                }
                mColorListeners.add(new Pair<>(callback, handler));
            }
        }

        /**
         * Stop listening to wallpaper color events.
         *
         * @param callback listener
         */
        public void removeOnColorsChangedListener(@NonNull OnColorsChangedListener callback) {
            synchronized (this) {
                mColorListeners.removeIf(pair -> pair.first == callback);

                if (mColorListeners.size() == 0 && mColorCallbackRegistered) {
                    mColorCallbackRegistered = false;
                    try {
                        mService.unregisterWallpaperColorsCallback(this);
                    } catch (RemoteException e) {
                        // Failed, service is gone
                        Log.w(TAG, "Can't unregister color updates", e);
                    }
                }
            }
        }

        @Override
        public void onWallpaperColorsChanged(WallpaperColors colors, int which) {
            synchronized (this) {
                for (Pair<OnColorsChangedListener, Handler> listener : mColorListeners) {
                    Handler handler = listener.second;
                    if (listener.second == null) {
                        handler = mMainLooperHandler;
                    }
                    handler.post(() -> {
                        // Dealing with race conditions between posting a callback and
                        // removeOnColorsChangedListener being called.
                        boolean stillExists;
                        synchronized (sGlobals) {
                            stillExists = mColorListeners.contains(listener);
                        }
                        if (stillExists) {
                            listener.first.onColorsChanged(colors, which);
                        }
                    });
                }
            }
        }

        WallpaperColors getWallpaperColors(int which) {
            synchronized (this) {
                if (which != FLAG_LOCK && which != FLAG_SYSTEM)
                    throw new IllegalArgumentException(
                            "which should be either FLAG_LOCK or FLAG_SYSTEM");

                try {
                    return mService.getWallpaperColors(which);
                } catch (RemoteException e) {
                    // Can't get colors, connection lost.
                }
                return null;
            }
        }

        public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault,
                @SetWallpaperFlags int which) {
            return peekWallpaperBitmap(context, returnDefault, which, context.getUserId());
@@ -746,7 +835,6 @@ public class WallpaperManager {
        return getWallpaperFile(which, mContext.getUserId());
    }


    /**
     * Registers a listener to get notified when the wallpaper colors change.
     * Callback might be called from an arbitrary background thread.
@@ -754,16 +842,18 @@ public class WallpaperManager {
     * @param listener A listener to register
     */
    public void addOnColorsChangedListener(@NonNull OnColorsChangedListener listener) {
        sGlobals.addOnColorsChangedListener(listener, null);
    }

    /**
     * Registers a listener to get notified when the wallpaper colors change
     * @param listener A listener to register
     * @param handler Where to call it from. Might be called from a background thread
     * @param handler Where to call it from. Will be called from the main thread
     *                if null.
     */
    public void addOnColorsChangedListener(@NonNull OnColorsChangedListener listener,
            @Nullable Handler handler) {
            @NonNull Handler handler) {
        sGlobals.addOnColorsChangedListener(listener, handler);
    }

    /**
@@ -771,6 +861,7 @@ public class WallpaperManager {
     * @param callback A callback to unsubscribe
     */
    public void removeOnColorsChangedListener(@NonNull OnColorsChangedListener callback) {
        sGlobals.removeOnColorsChangedListener(callback);
    }

    /**
@@ -780,7 +871,7 @@ public class WallpaperManager {
     * @return a list of colors ordered by priority
     */
    public @Nullable WallpaperColors getWallpaperColors(int which) {
        return null;
        return sGlobals.getWallpaperColors(which);
    }

    /**
@@ -1773,6 +1864,12 @@ public class WallpaperManager {
        public void onWallpaperChanged() throws RemoteException {
            mLatch.countDown();
        }

        @Override
        public void onWallpaperColorsChanged(WallpaperColors colors, int which)
            throws RemoteException {
            sGlobals.onWallpaperColorsChanged(colors, which);
        }
    }

    /**
Loading