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.systemui.statusbar.phone;
18 
19 import android.graphics.Rect;
20 import android.view.View;
21 
22 import com.android.systemui.Dependency;
23 import com.android.systemui.Dumpable;
24 import com.android.systemui.statusbar.policy.BatteryController;
25 import com.android.systemui.statusbar.policy.DarkIconDispatcher;
26 
27 import java.io.FileDescriptor;
28 import java.io.PrintWriter;
29 
30 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
31 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
32 
33 /**
34  * Controls how light status bar flag applies to the icons.
35  */
36 public class LightBarController implements BatteryController.BatteryStateChangeCallback, Dumpable {
37 
38     private static final float NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD = 0.1f;
39 
40     private final DarkIconDispatcher mStatusBarIconController;
41     private final BatteryController mBatteryController;
42     private FingerprintUnlockController mFingerprintUnlockController;
43 
44     private LightBarTransitionsController mNavigationBarController;
45     private int mSystemUiVisibility;
46     private int mFullscreenStackVisibility;
47     private int mDockedStackVisibility;
48     private boolean mFullscreenLight;
49     private boolean mDockedLight;
50     private int mLastStatusBarMode;
51     private int mLastNavigationBarMode;
52 
53     /**
54      * Whether the navigation bar should be light factoring in already how much alpha the scrim has
55      */
56     private boolean mNavigationLight;
57 
58     /**
59      * Whether the flags indicate that a light status bar is requested. This doesn't factor in the
60      * scrim alpha yet.
61      */
62     private boolean mHasLightNavigationBar;
63     private boolean mScrimAlphaBelowThreshold;
64     private float mScrimAlpha;
65 
66     private final Rect mLastFullscreenBounds = new Rect();
67     private final Rect mLastDockedBounds = new Rect();
68 
LightBarController()69     public LightBarController() {
70         mStatusBarIconController = Dependency.get(DarkIconDispatcher.class);
71         mBatteryController = Dependency.get(BatteryController.class);
72         mBatteryController.addCallback(this);
73     }
74 
setNavigationBar(LightBarTransitionsController navigationBar)75     public void setNavigationBar(LightBarTransitionsController navigationBar) {
76         mNavigationBarController = navigationBar;
77     }
78 
setFingerprintUnlockController( FingerprintUnlockController fingerprintUnlockController)79     public void setFingerprintUnlockController(
80             FingerprintUnlockController fingerprintUnlockController) {
81         mFingerprintUnlockController = fingerprintUnlockController;
82     }
83 
onSystemUiVisibilityChanged(int fullscreenStackVis, int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, boolean sbModeChanged, int statusBarMode)84     public void onSystemUiVisibilityChanged(int fullscreenStackVis, int dockedStackVis,
85             int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, boolean sbModeChanged,
86             int statusBarMode) {
87         int oldFullscreen = mFullscreenStackVisibility;
88         int newFullscreen = (oldFullscreen & ~mask) | (fullscreenStackVis & mask);
89         int diffFullscreen = newFullscreen ^ oldFullscreen;
90         int oldDocked = mDockedStackVisibility;
91         int newDocked = (oldDocked & ~mask) | (dockedStackVis & mask);
92         int diffDocked = newDocked ^ oldDocked;
93         if ((diffFullscreen & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0
94                 || (diffDocked & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0
95                 || sbModeChanged
96                 || !mLastFullscreenBounds.equals(fullscreenStackBounds)
97                 || !mLastDockedBounds.equals(dockedStackBounds)) {
98 
99             mFullscreenLight = isLight(newFullscreen, statusBarMode,
100                     View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
101             mDockedLight = isLight(newDocked, statusBarMode, View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
102             updateStatus(fullscreenStackBounds, dockedStackBounds);
103         }
104 
105         mFullscreenStackVisibility = newFullscreen;
106         mDockedStackVisibility = newDocked;
107         mLastStatusBarMode = statusBarMode;
108         mLastFullscreenBounds.set(fullscreenStackBounds);
109         mLastDockedBounds.set(dockedStackBounds);
110     }
111 
onNavigationVisibilityChanged(int vis, int mask, boolean nbModeChanged, int navigationBarMode)112     public void onNavigationVisibilityChanged(int vis, int mask, boolean nbModeChanged,
113             int navigationBarMode) {
114         int oldVis = mSystemUiVisibility;
115         int newVis = (oldVis & ~mask) | (vis & mask);
116         int diffVis = newVis ^ oldVis;
117         if ((diffVis & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0
118                 || nbModeChanged) {
119             boolean last = mNavigationLight;
120             mHasLightNavigationBar = isLight(vis, navigationBarMode,
121                     View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
122             mNavigationLight = mHasLightNavigationBar && mScrimAlphaBelowThreshold;
123             if (mNavigationLight != last) {
124                 updateNavigation();
125             }
126         }
127         mSystemUiVisibility = newVis;
128         mLastNavigationBarMode = navigationBarMode;
129     }
130 
reevaluate()131     private void reevaluate() {
132         onSystemUiVisibilityChanged(mFullscreenStackVisibility,
133                 mDockedStackVisibility, 0 /* mask */, mLastFullscreenBounds, mLastDockedBounds,
134                 true /* sbModeChange*/, mLastStatusBarMode);
135         onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */, true /* nbModeChanged */,
136                 mLastNavigationBarMode);
137     }
138 
setScrimAlpha(float alpha)139     public void setScrimAlpha(float alpha) {
140         mScrimAlpha = alpha;
141         boolean belowThresholdBefore = mScrimAlphaBelowThreshold;
142         mScrimAlphaBelowThreshold = mScrimAlpha < NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD;
143         if (mHasLightNavigationBar && belowThresholdBefore != mScrimAlphaBelowThreshold) {
144             reevaluate();
145         }
146     }
147 
148     private boolean isLight(int vis, int barMode, int flag) {
149         boolean isTransparentBar = (barMode == MODE_TRANSPARENT
150                 || barMode == MODE_LIGHTS_OUT_TRANSPARENT);
151         boolean allowLight = isTransparentBar && !mBatteryController.isPowerSave();
152         boolean light = (vis & flag) != 0;
153         return allowLight && light;
154     }
155 
156     private boolean animateChange() {
157         if (mFingerprintUnlockController == null) {
158             return false;
159         }
160         int unlockMode = mFingerprintUnlockController.getMode();
161         return unlockMode != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
162                 && unlockMode != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
163     }
164 
165     private void updateStatus(Rect fullscreenStackBounds, Rect dockedStackBounds) {
166         boolean hasDockedStack = !dockedStackBounds.isEmpty();
167 
168         // If both are light or fullscreen is light and there is no docked stack, all icons get
169         // dark.
170         if ((mFullscreenLight && mDockedLight) || (mFullscreenLight && !hasDockedStack)) {
171             mStatusBarIconController.setIconsDarkArea(null);
172             mStatusBarIconController.getTransitionsController().setIconsDark(true, animateChange());
173 
174         }
175 
176         // If no one is light or the fullscreen is not light and there is no docked stack,
177         // all icons become white.
178         else if ((!mFullscreenLight && !mDockedLight) || (!mFullscreenLight && !hasDockedStack)) {
179             mStatusBarIconController.getTransitionsController().setIconsDark(
180                     false, animateChange());
181         }
182 
183         // Not the same for every stack, magic!
184         else {
185             Rect bounds = mFullscreenLight ? fullscreenStackBounds : dockedStackBounds;
186             if (bounds.isEmpty()) {
187                 mStatusBarIconController.setIconsDarkArea(null);
188             } else {
189                 mStatusBarIconController.setIconsDarkArea(bounds);
190             }
191             mStatusBarIconController.getTransitionsController().setIconsDark(true, animateChange());
192         }
193     }
194 
195     private void updateNavigation() {
196         if (mNavigationBarController != null) {
197             mNavigationBarController.setIconsDark(
198                     mNavigationLight, animateChange());
199         }
200     }
201 
202     @Override
203     public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
204 
205     }
206 
207     @Override
208     public void onPowerSaveChanged(boolean isPowerSave) {
209         reevaluate();
210     }
211 
212     @Override
213     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
214         pw.println("LightBarController: ");
215         pw.print(" mSystemUiVisibility=0x"); pw.print(
216                 Integer.toHexString(mSystemUiVisibility));
217         pw.print(" mFullscreenStackVisibility=0x"); pw.print(
218                 Integer.toHexString(mFullscreenStackVisibility));
219         pw.print(" mDockedStackVisibility=0x"); pw.println(
220                 Integer.toHexString(mDockedStackVisibility));
221 
222         pw.print(" mFullscreenLight="); pw.print(mFullscreenLight);
223         pw.print(" mDockedLight="); pw.println(mDockedLight);
224 
225         pw.print(" mLastFullscreenBounds="); pw.print(mLastFullscreenBounds);
226         pw.print(" mLastDockedBounds="); pw.println(mLastDockedBounds);
227 
228         pw.print(" mNavigationLight="); pw.print(mNavigationLight);
229         pw.print(" mHasLightNavigationBar="); pw.println(mHasLightNavigationBar);
230 
231         pw.print(" mLastStatusBarMode="); pw.print(mLastStatusBarMode);
232         pw.print(" mLastNavigationBarMode="); pw.println(mLastNavigationBarMode);
233 
234         pw.print(" mScrimAlpha="); pw.print(mScrimAlpha);
235         pw.print(" mScrimAlphaBelowThreshold="); pw.println(mScrimAlphaBelowThreshold);
236         pw.println();
237         pw.println(" StatusBarTransitionsController:");
238         mStatusBarIconController.getTransitionsController().dump(fd, pw, args);
239         pw.println();
240         pw.println(" NavigationBarTransitionsController:");
241         mNavigationBarController.dump(fd, pw, args);
242         pw.println();
243     }
244 }
245