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