Home | History | Annotate | Download | only in dynamicui
      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      */
     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 */
     61     public static void startColorExtractionService(Context context) {
     62         context.startService(new Intent(context, ColorExtractionService.class));
     63     }
     64 
     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 
     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 
     86     public static boolean isSuperLight(Palette p) {
     87         return !isLegibleOnWallpaper(Color.WHITE, p.getSwatches());
     88     }
     89 
     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      */
     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. */
    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