1c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin/*
2c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin * Copyright (C) 2017 The Android Open Source Project
3c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin *
4c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin * Licensed under the Apache License, Version 2.0 (the "License");
5c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin * you may not use this file except in compliance with the License.
6c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin * You may obtain a copy of the License at
7c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin *
8c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin *      http://www.apache.org/licenses/LICENSE-2.0
9c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin *
10c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin * Unless required by applicable law or agreed to in writing, software
11c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin * distributed under the License is distributed on an "AS IS" BASIS,
12c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin * See the License for the specific language governing permissions and
14c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin * limitations under the License
15c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin */
16c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin
17c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupinpackage android.app;
18c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin
1984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupinimport android.annotation.NonNull;
2084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupinimport android.annotation.Nullable;
2184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupinimport android.graphics.Bitmap;
2284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupinimport android.graphics.Canvas;
23c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupinimport android.graphics.Color;
24ffbf37e61141d0694d47565e60ff713f72c19532Lucas Dupinimport android.graphics.Rect;
2584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupinimport android.graphics.drawable.Drawable;
26c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupinimport android.os.Parcel;
27c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupinimport android.os.Parcelable;
2884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupinimport android.util.Size;
29c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin
304bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupinimport com.android.internal.graphics.ColorUtils;
3184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupinimport com.android.internal.graphics.palette.Palette;
321d3c00d5c7a906d5a75ff66e05c7a865ff82fd4eLucas Dupinimport com.android.internal.graphics.palette.VariationalKMeansQuantizer;
33c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin
34ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupinimport java.util.ArrayList;
3584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupinimport java.util.Collections;
36c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupinimport java.util.List;
37c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin
38c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin/**
3984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin * Provides information about the colors of a wallpaper.
4084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin * <p>
41bdffdd52fa37bb94470a6ef079fb4163b5609f70Lucas Dupin * Exposes the 3 most visually representative colors of a wallpaper. Can be either
4284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin * {@link WallpaperColors#getPrimaryColor()}, {@link WallpaperColors#getSecondaryColor()}
4384b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin * or {@link WallpaperColors#getTertiaryColor()}.
44c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin */
45c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupinpublic final class WallpaperColors implements Parcelable {
46c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin
4784b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    /**
4884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * Specifies that dark text is preferred over the current wallpaper for best presentation.
4984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * <p>
5084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * eg. A launcher may set its text color to black if this flag is specified.
51bdffdd52fa37bb94470a6ef079fb4163b5609f70Lucas Dupin     * @hide
5284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     */
53e2efebc8a25d1bd44e588cc81f825d6337d87a23Lucas Dupin    public static final int HINT_SUPPORTS_DARK_TEXT = 1 << 0;
5484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
554bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin    /**
564bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin     * Specifies that dark theme is preferred over the current wallpaper for best presentation.
574bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin     * <p>
584bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin     * eg. A launcher may set its drawer color to black if this flag is specified.
594bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin     * @hide
604bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin     */
61e2efebc8a25d1bd44e588cc81f825d6337d87a23Lucas Dupin    public static final int HINT_SUPPORTS_DARK_THEME = 1 << 1;
62e2efebc8a25d1bd44e588cc81f825d6337d87a23Lucas Dupin
63e2efebc8a25d1bd44e588cc81f825d6337d87a23Lucas Dupin    /**
64e2efebc8a25d1bd44e588cc81f825d6337d87a23Lucas Dupin     * Specifies that this object was generated by extracting colors from a bitmap.
65e2efebc8a25d1bd44e588cc81f825d6337d87a23Lucas Dupin     * @hide
66e2efebc8a25d1bd44e588cc81f825d6337d87a23Lucas Dupin     */
67e2efebc8a25d1bd44e588cc81f825d6337d87a23Lucas Dupin    public static final int HINT_FROM_BITMAP = 1 << 2;
684bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin
6984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    // Maximum size that a bitmap can have to keep our calculations sane
7084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    private static final int MAX_BITMAP_SIZE = 112;
7184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
7284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    // Even though we have a maximum size, we'll mainly match bitmap sizes
7384b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    // using the area instead. This way our comparisons are aspect ratio independent.
7484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    private static final int MAX_WALLPAPER_EXTRACTION_AREA = MAX_BITMAP_SIZE * MAX_BITMAP_SIZE;
7584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
7684b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    // When extracting the main colors, only consider colors
7784b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    // present in at least MIN_COLOR_OCCURRENCE of the image
7884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    private static final float MIN_COLOR_OCCURRENCE = 0.05f;
7984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
804bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin    // Decides when dark theme is optimal for this wallpaper
814bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin    private static final float DARK_THEME_MEAN_LUMINANCE = 0.25f;
8284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    // Minimum mean luminosity that an image needs to have to support dark text
834bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin    private static final float BRIGHT_IMAGE_MEAN_LUMINANCE = 0.75f;
8484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    // We also check if the image has dark pixels in it,
8584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    // to avoid bright images with some dark spots.
8684b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    private static final float DARK_PIXEL_LUMINANCE = 0.45f;
8784b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    private static final float MAX_DARK_AREA = 0.05f;
8884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
8984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    private final ArrayList<Color> mMainColors;
9084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    private int mColorHints;
91ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin
92c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin    public WallpaperColors(Parcel parcel) {
9384b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        mMainColors = new ArrayList<>();
9484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        final int count = parcel.readInt();
9584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        for (int i = 0; i < count; i++) {
9684b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            final int colorInt = parcel.readInt();
9784b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            Color color = Color.valueOf(colorInt);
9884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            mMainColors.add(color);
99ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin        }
10084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        mColorHints = parcel.readInt();
101c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin    }
102c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin
103c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin    /**
10484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * Constructs {@link WallpaperColors} from a drawable.
10584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * <p>
106bdffdd52fa37bb94470a6ef079fb4163b5609f70Lucas Dupin     * Main colors will be extracted from the drawable.
107c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin     *
10884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * @param drawable Source where to extract from.
10984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     */
11084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    public static WallpaperColors fromDrawable(Drawable drawable) {
111ffbf37e61141d0694d47565e60ff713f72c19532Lucas Dupin        if (drawable == null) {
112ffbf37e61141d0694d47565e60ff713f72c19532Lucas Dupin            throw new IllegalArgumentException("Drawable cannot be null");
113ffbf37e61141d0694d47565e60ff713f72c19532Lucas Dupin        }
114ffbf37e61141d0694d47565e60ff713f72c19532Lucas Dupin
115ffbf37e61141d0694d47565e60ff713f72c19532Lucas Dupin        Rect initialBounds = drawable.copyBounds();
11684b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        int width = drawable.getIntrinsicWidth();
11784b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        int height = drawable.getIntrinsicHeight();
11884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
11984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        // Some drawables do not have intrinsic dimensions
12084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        if (width <= 0 || height <= 0) {
12184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            width = MAX_BITMAP_SIZE;
12284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            height = MAX_BITMAP_SIZE;
12384b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        }
12484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
12584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        Size optimalSize = calculateOptimalSize(width, height);
12684b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        Bitmap bitmap = Bitmap.createBitmap(optimalSize.getWidth(), optimalSize.getHeight(),
12784b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin                Bitmap.Config.ARGB_8888);
12884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        final Canvas bmpCanvas = new Canvas(bitmap);
12984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        drawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
13084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        drawable.draw(bmpCanvas);
13184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
13284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        final WallpaperColors colors = WallpaperColors.fromBitmap(bitmap);
13384b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        bitmap.recycle();
13484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
135ffbf37e61141d0694d47565e60ff713f72c19532Lucas Dupin        drawable.setBounds(initialBounds);
13684b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        return colors;
13784b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    }
13884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
13984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    /**
14084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * Constructs {@link WallpaperColors} from a bitmap.
14184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * <p>
142bdffdd52fa37bb94470a6ef079fb4163b5609f70Lucas Dupin     * Main colors will be extracted from the bitmap.
143c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin     *
14484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * @param bitmap Source where to extract from.
145c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin     */
14684b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    public static WallpaperColors fromBitmap(@NonNull Bitmap bitmap) {
14784b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        if (bitmap == null) {
14884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            throw new IllegalArgumentException("Bitmap can't be null");
14984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        }
15084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
15184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        final int bitmapArea = bitmap.getWidth() * bitmap.getHeight();
15242acf6009ade4314f3cd782d68db6ab7ad4c8da3Lucas Dupin        boolean shouldRecycle = false;
15384b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        if (bitmapArea > MAX_WALLPAPER_EXTRACTION_AREA) {
15442acf6009ade4314f3cd782d68db6ab7ad4c8da3Lucas Dupin            shouldRecycle = true;
15584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            Size optimalSize = calculateOptimalSize(bitmap.getWidth(), bitmap.getHeight());
15642acf6009ade4314f3cd782d68db6ab7ad4c8da3Lucas Dupin            bitmap = Bitmap.createScaledBitmap(bitmap, optimalSize.getWidth(),
15784b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin                    optimalSize.getHeight(), true /* filter */);
15884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        }
15984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
16084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        final Palette palette = Palette
16184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin                .from(bitmap)
1621d3c00d5c7a906d5a75ff66e05c7a865ff82fd4eLucas Dupin                .setQuantizer(new VariationalKMeansQuantizer())
1631d3c00d5c7a906d5a75ff66e05c7a865ff82fd4eLucas Dupin                .maximumColorCount(5)
16484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin                .clearFilters()
16584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin                .resizeBitmapArea(MAX_WALLPAPER_EXTRACTION_AREA)
16684b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin                .generate();
16784b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
16884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        // Remove insignificant colors and sort swatches by population
16984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        final ArrayList<Palette.Swatch> swatches = new ArrayList<>(palette.getSwatches());
17084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        final float minColorArea = bitmap.getWidth() * bitmap.getHeight() * MIN_COLOR_OCCURRENCE;
17184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        swatches.removeIf(s -> s.getPopulation() < minColorArea);
17284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        swatches.sort((a, b) -> b.getPopulation() - a.getPopulation());
17384b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
17484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        final int swatchesSize = swatches.size();
17584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        Color primary = null, secondary = null, tertiary = null;
17684b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
17784b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        swatchLoop:
17884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        for (int i = 0; i < swatchesSize; i++) {
17984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            Color color = Color.valueOf(swatches.get(i).getRgb());
18084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            switch (i) {
18184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin                case 0:
18284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin                    primary = color;
18384b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin                    break;
18484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin                case 1:
18584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin                    secondary = color;
18684b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin                    break;
18784b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin                case 2:
18884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin                    tertiary = color;
18984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin                    break;
19084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin                default:
19184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin                    // out of bounds
19284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin                    break swatchLoop;
19384b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            }
19484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        }
19584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
196b5e5053ebc442ced1ad702f551919bc533bee164Lucas Dupin        int hints = calculateDarkHints(bitmap);
19742acf6009ade4314f3cd782d68db6ab7ad4c8da3Lucas Dupin
19842acf6009ade4314f3cd782d68db6ab7ad4c8da3Lucas Dupin        if (shouldRecycle) {
19942acf6009ade4314f3cd782d68db6ab7ad4c8da3Lucas Dupin            bitmap.recycle();
20042acf6009ade4314f3cd782d68db6ab7ad4c8da3Lucas Dupin        }
20142acf6009ade4314f3cd782d68db6ab7ad4c8da3Lucas Dupin
202e2efebc8a25d1bd44e588cc81f825d6337d87a23Lucas Dupin        return new WallpaperColors(primary, secondary, tertiary, HINT_FROM_BITMAP | hints);
203c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin    }
204c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin
205c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin    /**
206bdffdd52fa37bb94470a6ef079fb4163b5609f70Lucas Dupin     * Constructs a new object from three colors.
207bdffdd52fa37bb94470a6ef079fb4163b5609f70Lucas Dupin     *
208bdffdd52fa37bb94470a6ef079fb4163b5609f70Lucas Dupin     * @param primaryColor Primary color.
209bdffdd52fa37bb94470a6ef079fb4163b5609f70Lucas Dupin     * @param secondaryColor Secondary color.
210bdffdd52fa37bb94470a6ef079fb4163b5609f70Lucas Dupin     * @param tertiaryColor Tertiary color.
211bdffdd52fa37bb94470a6ef079fb4163b5609f70Lucas Dupin     * @see WallpaperColors#fromBitmap(Bitmap)
212bdffdd52fa37bb94470a6ef079fb4163b5609f70Lucas Dupin     * @see WallpaperColors#fromDrawable(Drawable)
213bdffdd52fa37bb94470a6ef079fb4163b5609f70Lucas Dupin     */
214bdffdd52fa37bb94470a6ef079fb4163b5609f70Lucas Dupin    public WallpaperColors(@NonNull Color primaryColor, @Nullable Color secondaryColor,
215bdffdd52fa37bb94470a6ef079fb4163b5609f70Lucas Dupin            @Nullable Color tertiaryColor) {
216bdffdd52fa37bb94470a6ef079fb4163b5609f70Lucas Dupin        this(primaryColor, secondaryColor, tertiaryColor, 0);
217bdffdd52fa37bb94470a6ef079fb4163b5609f70Lucas Dupin    }
218bdffdd52fa37bb94470a6ef079fb4163b5609f70Lucas Dupin
219bdffdd52fa37bb94470a6ef079fb4163b5609f70Lucas Dupin    /**
22084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * Constructs a new object from three colors, where hints can be specified.
221c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin     *
22284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * @param primaryColor Primary color.
22384b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * @param secondaryColor Secondary color.
22484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * @param tertiaryColor Tertiary color.
22584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * @param colorHints A combination of WallpaperColor hints.
22684b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * @see WallpaperColors#HINT_SUPPORTS_DARK_TEXT
22784b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * @see WallpaperColors#fromBitmap(Bitmap)
22884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * @see WallpaperColors#fromDrawable(Drawable)
229bdffdd52fa37bb94470a6ef079fb4163b5609f70Lucas Dupin     * @hide
230c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin     */
23184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    public WallpaperColors(@NonNull Color primaryColor, @Nullable Color secondaryColor,
23284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            @Nullable Color tertiaryColor, int colorHints) {
23384b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
23484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        if (primaryColor == null) {
23584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            throw new IllegalArgumentException("Primary color should never be null.");
23684b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        }
23784b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
23884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        mMainColors = new ArrayList<>(3);
23984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        mMainColors.add(primaryColor);
24084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        if (secondaryColor != null) {
24184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            mMainColors.add(secondaryColor);
24284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        }
24384b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        if (tertiaryColor != null) {
24484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            if (secondaryColor == null) {
24584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin                throw new IllegalArgumentException("tertiaryColor can't be specified when "
24684b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin                        + "secondaryColor is null");
24784b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            }
24884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            mMainColors.add(tertiaryColor);
24984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        }
25084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
25184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        mColorHints = colorHints;
252c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin    }
253c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin
254c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin    public static final Creator<WallpaperColors> CREATOR = new Creator<WallpaperColors>() {
255c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin        @Override
256c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin        public WallpaperColors createFromParcel(Parcel in) {
257c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin            return new WallpaperColors(in);
258c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin        }
259c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin
260c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin        @Override
261c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin        public WallpaperColors[] newArray(int size) {
262c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin            return new WallpaperColors[size];
263c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin        }
264c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin    };
265c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin
266c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin    @Override
267c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin    public int describeContents() {
268c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin        return 0;
269c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin    }
270c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin
271c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin    @Override
272c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin    public void writeToParcel(Parcel dest, int flags) {
27384b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        List<Color> mainColors = getMainColors();
27484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        int count = mainColors.size();
275ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin        dest.writeInt(count);
27684b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        for (int i = 0; i < count; i++) {
27784b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            Color color = mainColors.get(i);
27884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            dest.writeInt(color.toArgb());
279ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin        }
28084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        dest.writeInt(mColorHints);
28184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    }
28284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
28384b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    /**
28484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * Gets the most visually representative color of the wallpaper.
28584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * "Visually representative" means easily noticeable in the image,
28684b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * probably happening at high frequency.
28784b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     *
28884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * @return A color.
28984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     */
29084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    public @NonNull Color getPrimaryColor() {
29184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        return mMainColors.get(0);
29284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    }
29384b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
29484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    /**
29584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * Gets the second most preeminent color of the wallpaper. Can be null.
29684b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     *
29784b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * @return A color, may be null.
29884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     */
29984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    public @Nullable Color getSecondaryColor() {
30084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        return mMainColors.size() < 2 ? null : mMainColors.get(1);
30184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    }
30284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
30384b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    /**
30484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * Gets the third most preeminent color of the wallpaper. Can be null.
30584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     *
30684b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * @return A color, may be null.
30784b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     */
30884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    public @Nullable Color getTertiaryColor() {
30984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        return mMainColors.size() < 3 ? null : mMainColors.get(2);
310c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin    }
311c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin
312c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin    /**
31384b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * List of most preeminent colors, sorted by importance.
31484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     *
31584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * @return List of colors.
31684b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * @hide
317c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin     */
31884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    public @NonNull List<Color> getMainColors() {
31984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        return Collections.unmodifiableList(mMainColors);
320ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin    }
321ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin
322ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin    @Override
323ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin    public boolean equals(Object o) {
324ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin        if (o == null || getClass() != o.getClass()) {
325ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin            return false;
326ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin        }
327ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin
328ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin        WallpaperColors other = (WallpaperColors) o;
32984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        return mMainColors.equals(other.mMainColors)
33084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin                && mColorHints == other.mColorHints;
331ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin    }
332ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin
333ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin    @Override
334ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin    public int hashCode() {
33584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        return 31 * mMainColors.hashCode() + mColorHints;
336c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin    }
337c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin
338c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin    /**
33984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * Combination of WallpaperColor hints.
340c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin     *
34184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * @see WallpaperColors#HINT_SUPPORTS_DARK_TEXT
34284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * @return True if dark text is supported.
343bdffdd52fa37bb94470a6ef079fb4163b5609f70Lucas Dupin     * @hide
34484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     */
34584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    public int getColorHints() {
34684b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        return mColorHints;
34784b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    }
34884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
34984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    /**
35084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * @param colorHints Combination of WallpaperColors hints.
35184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * @see WallpaperColors#HINT_SUPPORTS_DARK_TEXT
35284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * @hide
353c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin     */
35484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    public void setColorHints(int colorHints) {
35584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        mColorHints = colorHints;
356ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin    }
357ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin
35884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    /**
35984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * Checks if image is bright and clean enough to support light text.
36084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     *
36184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * @param source What to read.
36284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     * @return Whether image supports dark text or not.
36384b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin     */
364e2efebc8a25d1bd44e588cc81f825d6337d87a23Lucas Dupin    private static int calculateDarkHints(Bitmap source) {
36584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        if (source == null) {
3664bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin            return 0;
367ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin        }
368ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin
36984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        int[] pixels = new int[source.getWidth() * source.getHeight()];
37084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        double totalLuminance = 0;
37184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        final int maxDarkPixels = (int) (pixels.length * MAX_DARK_AREA);
37284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        int darkPixels = 0;
37384b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        source.getPixels(pixels, 0 /* offset */, source.getWidth(), 0 /* x */, 0 /* y */,
37484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin                source.getWidth(), source.getHeight());
375ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin
37684b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        // This bitmap was already resized to fit the maximum allowed area.
37784b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        // Let's just loop through the pixels, no sweat!
3784bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin        float[] tmpHsl = new float[3];
37984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        for (int i = 0; i < pixels.length; i++) {
3804bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin            ColorUtils.colorToHSL(pixels[i], tmpHsl);
3814bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin            final float luminance = tmpHsl[2];
38284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            final int alpha = Color.alpha(pixels[i]);
38384b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            // Make sure we don't have a dark pixel mass that will
38484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            // make text illegible.
38584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            if (luminance < DARK_PIXEL_LUMINANCE && alpha != 0) {
38684b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin                darkPixels++;
387ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin            }
38884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            totalLuminance += luminance;
38984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        }
3904bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin
3914bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin        int hints = 0;
3924bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin        double meanLuminance = totalLuminance / pixels.length;
3934bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin        if (meanLuminance > BRIGHT_IMAGE_MEAN_LUMINANCE && darkPixels < maxDarkPixels) {
3944bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin            hints |= HINT_SUPPORTS_DARK_TEXT;
3954bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin        }
3964bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin        if (meanLuminance < DARK_THEME_MEAN_LUMINANCE) {
3974bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin            hints |= HINT_SUPPORTS_DARK_THEME;
3984bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin        }
3994bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin
4004bd24f36c5c4845bc9fda9c7211d1be2937a748aLucas Dupin        return hints;
40184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    }
40284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
40384b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin    private static Size calculateOptimalSize(int width, int height) {
40484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        // Calculate how big the bitmap needs to be.
40584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        // This avoids unnecessary processing and allocation inside Palette.
40684b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        final int requestedArea = width * height;
40784b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        double scale = 1;
40884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        if (requestedArea > MAX_WALLPAPER_EXTRACTION_AREA) {
40984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            scale = Math.sqrt(MAX_WALLPAPER_EXTRACTION_AREA / (double) requestedArea);
41084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        }
41184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        int newWidth = (int) (width * scale);
41284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        int newHeight = (int) (height * scale);
41384b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        // Dealing with edge cases of the drawable being too wide or too tall.
41484b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        // Width or height would end up being 0, in this case we'll set it to 1.
41584b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        if (newWidth == 0) {
41684b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            newWidth = 1;
417ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin        }
41884b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        if (newHeight == 0) {
41984b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin            newHeight = 1;
42084b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        }
42184b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin
42284b89d9d59797483a7e4a1bf82f3819d81e696e9Lucas Dupin        return new Size(newWidth, newHeight);
423c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin    }
42450ba991655555dfde90149489f6485a0529ba0acLucas Dupin
42550ba991655555dfde90149489f6485a0529ba0acLucas Dupin    @Override
42650ba991655555dfde90149489f6485a0529ba0acLucas Dupin    public String toString() {
42750ba991655555dfde90149489f6485a0529ba0acLucas Dupin        final StringBuilder colors = new StringBuilder();
42850ba991655555dfde90149489f6485a0529ba0acLucas Dupin        for (int i = 0; i < mMainColors.size(); i++) {
42950ba991655555dfde90149489f6485a0529ba0acLucas Dupin            colors.append(Integer.toHexString(mMainColors.get(i).toArgb())).append(" ");
43050ba991655555dfde90149489f6485a0529ba0acLucas Dupin        }
43150ba991655555dfde90149489f6485a0529ba0acLucas Dupin        return "[WallpaperColors: " + colors.toString() + "h: " + mColorHints + "]";
43250ba991655555dfde90149489f6485a0529ba0acLucas Dupin    }
433c40608c041b1eb8b8cb4b96347c7ca29f4f79169Lucas Dupin}
434