1 /*
2  * Copyright (C) 2018 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.systemui.plugins;
18 
19 import android.graphics.Color;
20 import android.graphics.Rect;
21 import android.view.View;
22 import android.widget.ImageView;
23 
24 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
25 import com.android.systemui.plugins.annotations.DependsOn;
26 import com.android.systemui.plugins.annotations.ProvidesInterface;
27 
28 import java.util.ArrayList;
29 import java.util.Collection;
30 
31 /**
32  * Dispatches events to {@link DarkReceiver}s about changes in darkness, tint area and dark
33  * intensity. Accessible through {@link PluginDependency}
34  */
35 @ProvidesInterface(version = DarkIconDispatcher.VERSION)
36 @DependsOn(target = DarkReceiver.class)
37 public interface DarkIconDispatcher {
38     int VERSION = 2;
39 
40     /**
41      * Sets the dark area so {@link #applyDark} only affects the icons in the specified area.
42      *
43      * @param r the areas in which icons should change its tint, in logical screen
44      *                 coordinates
45      */
setIconsDarkArea(ArrayList<Rect> r)46     void setIconsDarkArea(ArrayList<Rect> r);
47 
48     /**
49      * Adds a receiver to receive callbacks onDarkChanged
50      */
addDarkReceiver(DarkReceiver receiver)51     void addDarkReceiver(DarkReceiver receiver);
52 
53     /**
54      * Adds a receiver to receive callbacks onDarkChanged
55      */
addDarkReceiver(ImageView imageView)56     void addDarkReceiver(ImageView imageView);
57 
58     /**
59      * Must have been previously been added through one of the addDarkReceive methods above.
60      */
removeDarkReceiver(DarkReceiver object)61     void removeDarkReceiver(DarkReceiver object);
62 
63     /**
64      * Must have been previously been added through one of the addDarkReceive methods above.
65      */
removeDarkReceiver(ImageView object)66     void removeDarkReceiver(ImageView object);
67 
68     /**
69      * Used to reapply darkness on an object, must have previously been added through
70      * addDarkReceiver.
71       */
applyDark(DarkReceiver object)72     void applyDark(DarkReceiver object);
73 
74     int DEFAULT_ICON_TINT = Color.WHITE;
75     Rect sTmpRect = new Rect();
76     int[] sTmpInt2 = new int[2];
77 
78     /**
79      * @return the tint to apply to view depending on the desired tint color and
80      *         the screen tintArea in which to apply that tint
81      */
getTint(Collection<Rect> tintAreas, View view, int color)82     static int getTint(Collection<Rect> tintAreas, View view, int color) {
83         if (isInAreas(tintAreas, view)) {
84             return color;
85         } else {
86             return DEFAULT_ICON_TINT;
87         }
88     }
89 
90     /**
91      * @return true if more than half of the view area are in any of the given
92      *         areas, false otherwise
93      */
isInAreas(Collection<Rect> areas, View view)94     static boolean isInAreas(Collection<Rect> areas, View view) {
95         if (areas.isEmpty()) {
96             return true;
97         }
98         for (Rect area : areas) {
99             if (isInArea(area, view)) {
100                 return true;
101             }
102         }
103         return false;
104     }
105 
106     /**
107      * @return true if more than half of the view area are in area, false
108      *         otherwise
109      */
isInArea(Rect area, View view)110     static boolean isInArea(Rect area, View view) {
111         if (area.isEmpty()) {
112             return true;
113         }
114         sTmpRect.set(area);
115         view.getLocationOnScreen(sTmpInt2);
116         int left = sTmpInt2[0];
117 
118         int intersectStart = Math.max(left, area.left);
119         int intersectEnd = Math.min(left + view.getWidth(), area.right);
120         int intersectAmount = Math.max(0, intersectEnd - intersectStart);
121 
122         boolean coversFullStatusBar = area.top <= 0;
123         boolean majorityOfWidth = 2 * intersectAmount > view.getWidth();
124         return majorityOfWidth && coversFullStatusBar;
125     }
126 
127     /**
128      * Receives a callback on darkness changes
129      */
130     @ProvidesInterface(version = DarkReceiver.VERSION)
131     interface DarkReceiver {
132         int VERSION = 2;
onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint)133         void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint);
134     }
135 }
136