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