• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.launcher3.dynamicui;
18 
19 import android.app.WallpaperManager;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.SharedPreferences;
23 import android.graphics.Color;
24 import android.support.v4.graphics.ColorUtils;
25 import android.support.v7.graphics.Palette;
26 
27 import com.android.launcher3.Utilities;
28 
29 import java.lang.reflect.InvocationTargetException;
30 import java.lang.reflect.Method;
31 import java.util.List;
32 
33 /**
34  * Contains helper fields and methods related to extracting colors from the wallpaper.
35  */
36 public class ExtractionUtils {
37     public static final String EXTRACTED_COLORS_PREFERENCE_KEY = "pref_extractedColors";
38     public static final String WALLPAPER_ID_PREFERENCE_KEY = "pref_wallpaperId";
39 
40     private static final int FLAG_SET_SYSTEM = 1 << 0; // TODO: use WallpaperManager.FLAG_SET_SYSTEM
41     private static final float MIN_CONTRAST_RATIO = 2f;
42 
43     /**
44      * Extract colors in the :wallpaper-chooser process, if the wallpaper id has changed.
45      * When the new colors are saved in the LauncherProvider,
46      * Launcher will be notified in Launcher#onSettingsChanged(String, String).
47      */
startColorExtractionServiceIfNecessary(final Context context)48     public static void startColorExtractionServiceIfNecessary(final Context context) {
49         // Run on a background thread, since the service is asynchronous anyway.
50         Utilities.THREAD_POOL_EXECUTOR.execute(new Runnable() {
51             @Override
52             public void run() {
53                 if (hasWallpaperIdChanged(context)) {
54                     startColorExtractionService(context);
55                 }
56             }
57         });
58     }
59 
60     /** Starts the {@link ColorExtractionService} without checking the wallpaper id */
startColorExtractionService(Context context)61     public static void startColorExtractionService(Context context) {
62         context.startService(new Intent(context, ColorExtractionService.class));
63     }
64 
hasWallpaperIdChanged(Context context)65     private static boolean hasWallpaperIdChanged(Context context) {
66         if (!Utilities.isNycOrAbove()) {
67             // TODO: update an id in sharedprefs in onWallpaperChanged broadcast, and read it here.
68             return false;
69         }
70         final SharedPreferences sharedPrefs = Utilities.getPrefs(context);
71         int wallpaperId = getWallpaperId(WallpaperManager.getInstance(context));
72         int savedWallpaperId = sharedPrefs.getInt(ExtractionUtils.WALLPAPER_ID_PREFERENCE_KEY, -1);
73         return wallpaperId != savedWallpaperId;
74     }
75 
getWallpaperId(WallpaperManager wallpaperManager)76     public static int getWallpaperId(WallpaperManager wallpaperManager) {
77         // TODO: use WallpaperManager#getWallpaperId(WallpaperManager.FLAG_SET_SYSTEM) directly.
78         try {
79             Method getWallpaperId = WallpaperManager.class.getMethod("getWallpaperId", int.class);
80             return (int) getWallpaperId.invoke(wallpaperManager, FLAG_SET_SYSTEM);
81         } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
82             return -1;
83         }
84     }
85 
isSuperLight(Palette p)86     public static boolean isSuperLight(Palette p) {
87         return !isLegibleOnWallpaper(Color.WHITE, p.getSwatches());
88     }
89 
isSuperDark(Palette p)90     public static boolean isSuperDark(Palette p) {
91         return !isLegibleOnWallpaper(Color.BLACK, p.getSwatches());
92     }
93 
94     /**
95      * Given a color, returns true if that color is legible on
96      * the given wallpaper color swatches, else returns false.
97      */
isLegibleOnWallpaper(int color, List<Palette.Swatch> wallpaperSwatches)98     private static boolean isLegibleOnWallpaper(int color, List<Palette.Swatch> wallpaperSwatches) {
99         int legiblePopulation = 0;
100         int illegiblePopulation = 0;
101         for (Palette.Swatch swatch : wallpaperSwatches) {
102             if (isLegible(color, swatch.getRgb())) {
103                 legiblePopulation += swatch.getPopulation();
104             } else {
105                 illegiblePopulation += swatch.getPopulation();
106             }
107         }
108         return legiblePopulation > illegiblePopulation;
109     }
110 
111     /** @return Whether the foreground color is legible on the background color. */
isLegible(int foreground, int background)112     private static boolean isLegible(int foreground, int background) {
113         background = ColorUtils.setAlphaComponent(background, 255);
114         return ColorUtils.calculateContrast(foreground, background) >= MIN_CONTRAST_RATIO;
115     }
116 
117 }
118