summaryrefslogtreecommitdiff
path: root/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
blob: 732c115571f849957d0c9ca756b1dbe06b9412e4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
 * 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 com.android.systemui.statusbar.notification;

import android.graphics.Bitmap;
import android.graphics.Color;

import androidx.palette.graphics.Palette;

import java.util.List;

/**
 * A gutted class that now contains only a color extraction utility used by the
 * MediaArtworkProcessor, which has otherwise supplanted this.
 *
 * TODO(b/182926117): move this into MediaArtworkProcessor.kt
 */
public class MediaNotificationProcessor {

    /**
     * The population fraction to select a white or black color as the background over a color.
     */
    private static final float POPULATION_FRACTION_FOR_WHITE_OR_BLACK = 2.5f;
    private static final float BLACK_MAX_LIGHTNESS = 0.08f;
    private static final float WHITE_MIN_LIGHTNESS = 0.90f;
    private static final int RESIZE_BITMAP_AREA = 150 * 150;

    private MediaNotificationProcessor() {
    }

    /**
     * Finds an appropriate background swatch from media artwork.
     *
     * @param artwork Media artwork
     * @return Swatch that should be used as the background of the media notification.
     */
    public static Palette.Swatch findBackgroundSwatch(Bitmap artwork) {
        return findBackgroundSwatch(generateArtworkPaletteBuilder(artwork).generate());
    }

    /**
     * Finds an appropriate background swatch from the palette of media artwork.
     *
     * @param palette Artwork palette, should be obtained from {@link generateArtworkPaletteBuilder}
     * @return Swatch that should be used as the background of the media notification.
     */
    public static Palette.Swatch findBackgroundSwatch(Palette palette) {
        // by default we use the dominant palette
        Palette.Swatch dominantSwatch = palette.getDominantSwatch();
        if (dominantSwatch == null) {
            return new Palette.Swatch(Color.WHITE, 100);
        }

        if (!isWhiteOrBlack(dominantSwatch.getHsl())) {
            return dominantSwatch;
        }
        // Oh well, we selected black or white. Lets look at the second color!
        List<Palette.Swatch> swatches = palette.getSwatches();
        float highestNonWhitePopulation = -1;
        Palette.Swatch second = null;
        for (Palette.Swatch swatch : swatches) {
            if (swatch != dominantSwatch
                    && swatch.getPopulation() > highestNonWhitePopulation
                    && !isWhiteOrBlack(swatch.getHsl())) {
                second = swatch;
                highestNonWhitePopulation = swatch.getPopulation();
            }
        }
        if (second == null) {
            return dominantSwatch;
        }
        if (dominantSwatch.getPopulation() / highestNonWhitePopulation
                > POPULATION_FRACTION_FOR_WHITE_OR_BLACK) {
            // The dominant swatch is very dominant, lets take it!
            // We're not filtering on white or black
            return dominantSwatch;
        } else {
            return second;
        }
    }

    /**
     * Generate a palette builder for media artwork.
     *
     * For producing a smooth background transition, the palette is extracted from only the left
     * side of the artwork.
     *
     * @param artwork Media artwork
     * @return Builder that generates the {@link Palette} for the media artwork.
     */
    public static Palette.Builder generateArtworkPaletteBuilder(Bitmap artwork) {
        // for the background we only take the left side of the image to ensure
        // a smooth transition
        return Palette.from(artwork)
                .setRegion(0, 0, artwork.getWidth() / 2, artwork.getHeight())
                .clearFilters() // we want all colors, red / white / black ones too!
                .resizeBitmapArea(RESIZE_BITMAP_AREA);
    }

    private static boolean isWhiteOrBlack(float[] hsl) {
        return isBlack(hsl) || isWhite(hsl);
    }

    /**
     * @return true if the color represents a color which is close to black.
     */
    private static boolean isBlack(float[] hslColor) {
        return hslColor[2] <= BLACK_MAX_LIGHTNESS;
    }

    /**
     * @return true if the color represents a color which is close to white.
     */
    private static boolean isWhite(float[] hslColor) {
        return hslColor[2] >= WHITE_MIN_LIGHTNESS;
    }
}