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 static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT; 20 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT; 21 22 import android.content.Context; 23 import android.graphics.Color; 24 import android.graphics.Rect; 25 import android.view.View; 26 27 import com.android.internal.colorextraction.ColorExtractor.GradientColors; 28 import com.android.systemui.Dumpable; 29 import com.android.systemui.R; 30 import com.android.systemui.plugins.DarkIconDispatcher; 31 import com.android.systemui.statusbar.policy.BatteryController; 32 33 import java.io.FileDescriptor; 34 import java.io.PrintWriter; 35 36 import javax.inject.Inject; 37 import javax.inject.Singleton; 38 39 /** 40 * Controls how light status bar flag applies to the icons. 41 */ 42 @Singleton 43 public class LightBarController implements BatteryController.BatteryStateChangeCallback, Dumpable { 44 45 private static final float NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD = 0.1f; 46 47 private final SysuiDarkIconDispatcher mStatusBarIconController; 48 private final BatteryController mBatteryController; 49 private BiometricUnlockController mBiometricUnlockController; 50 51 private LightBarTransitionsController mNavigationBarController; 52 private int mSystemUiVisibility; 53 private int mFullscreenStackVisibility; 54 private int mDockedStackVisibility; 55 private boolean mFullscreenLight; 56 private boolean mDockedLight; 57 private int mLastStatusBarMode; 58 private int mLastNavigationBarMode; 59 private final Color mDarkModeColor; 60 61 /** 62 * Whether the navigation bar should be light factoring in already how much alpha the scrim has 63 */ 64 private boolean mNavigationLight; 65 66 /** 67 * Whether the flags indicate that a light status bar is requested. This doesn't factor in the 68 * scrim alpha yet. 69 */ 70 private boolean mHasLightNavigationBar; 71 72 /** 73 * {@code true} if {@link #mHasLightNavigationBar} should be ignored and forcefully make 74 * {@link #mNavigationLight} {@code false}. 75 */ 76 private boolean mForceDarkForScrim; 77 78 private final Rect mLastFullscreenBounds = new Rect(); 79 private final Rect mLastDockedBounds = new Rect(); 80 private boolean mQsCustomizing; 81 82 private boolean mDirectReplying; 83 private boolean mNavbarColorManagedByIme; 84 85 @Inject LightBarController(Context ctx, DarkIconDispatcher darkIconDispatcher, BatteryController batteryController)86 public LightBarController(Context ctx, DarkIconDispatcher darkIconDispatcher, 87 BatteryController batteryController) { 88 mDarkModeColor = Color.valueOf(ctx.getColor(R.color.dark_mode_icon_color_single_tone)); 89 mStatusBarIconController = (SysuiDarkIconDispatcher) darkIconDispatcher; 90 mBatteryController = batteryController; 91 mBatteryController.addCallback(this); 92 } 93 setNavigationBar(LightBarTransitionsController navigationBar)94 public void setNavigationBar(LightBarTransitionsController navigationBar) { 95 mNavigationBarController = navigationBar; 96 updateNavigation(); 97 } 98 setBiometricUnlockController( BiometricUnlockController biometricUnlockController)99 public void setBiometricUnlockController( 100 BiometricUnlockController biometricUnlockController) { 101 mBiometricUnlockController = biometricUnlockController; 102 } 103 onSystemUiVisibilityChanged(int fullscreenStackVis, int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, boolean sbModeChanged, int statusBarMode, boolean navbarColorManagedByIme)104 public void onSystemUiVisibilityChanged(int fullscreenStackVis, int dockedStackVis, 105 int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, boolean sbModeChanged, 106 int statusBarMode, boolean navbarColorManagedByIme) { 107 int oldFullscreen = mFullscreenStackVisibility; 108 int newFullscreen = (oldFullscreen & ~mask) | (fullscreenStackVis & mask); 109 int diffFullscreen = newFullscreen ^ oldFullscreen; 110 int oldDocked = mDockedStackVisibility; 111 int newDocked = (oldDocked & ~mask) | (dockedStackVis & mask); 112 int diffDocked = newDocked ^ oldDocked; 113 if ((diffFullscreen & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0 114 || (diffDocked & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0 115 || sbModeChanged 116 || !mLastFullscreenBounds.equals(fullscreenStackBounds) 117 || !mLastDockedBounds.equals(dockedStackBounds)) { 118 119 mFullscreenLight = isLight(newFullscreen, statusBarMode, 120 View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); 121 mDockedLight = isLight(newDocked, statusBarMode, View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); 122 updateStatus(fullscreenStackBounds, dockedStackBounds); 123 } 124 125 mFullscreenStackVisibility = newFullscreen; 126 mDockedStackVisibility = newDocked; 127 mLastStatusBarMode = statusBarMode; 128 mNavbarColorManagedByIme = navbarColorManagedByIme; 129 mLastFullscreenBounds.set(fullscreenStackBounds); 130 mLastDockedBounds.set(dockedStackBounds); 131 } 132 onNavigationVisibilityChanged(int vis, int mask, boolean nbModeChanged, int navigationBarMode, boolean navbarColorManagedByIme)133 public void onNavigationVisibilityChanged(int vis, int mask, boolean nbModeChanged, 134 int navigationBarMode, boolean navbarColorManagedByIme) { 135 int oldVis = mSystemUiVisibility; 136 int newVis = (oldVis & ~mask) | (vis & mask); 137 int diffVis = newVis ^ oldVis; 138 if ((diffVis & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0 139 || nbModeChanged) { 140 boolean last = mNavigationLight; 141 mHasLightNavigationBar = isLight(vis, navigationBarMode, 142 View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR); 143 mNavigationLight = mHasLightNavigationBar 144 && (mDirectReplying && mNavbarColorManagedByIme || !mForceDarkForScrim) 145 && !mQsCustomizing; 146 if (mNavigationLight != last) { 147 updateNavigation(); 148 } 149 } 150 mSystemUiVisibility = newVis; 151 mLastNavigationBarMode = navigationBarMode; 152 mNavbarColorManagedByIme = navbarColorManagedByIme; 153 } 154 reevaluate()155 private void reevaluate() { 156 onSystemUiVisibilityChanged(mFullscreenStackVisibility, 157 mDockedStackVisibility, 0 /* mask */, mLastFullscreenBounds, mLastDockedBounds, 158 true /* sbModeChange*/, mLastStatusBarMode, mNavbarColorManagedByIme); 159 onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */, true /* nbModeChanged */, 160 mLastNavigationBarMode, mNavbarColorManagedByIme); 161 } 162 setQsCustomizing(boolean customizing)163 public void setQsCustomizing(boolean customizing) { 164 if (mQsCustomizing == customizing) return; 165 mQsCustomizing = customizing; 166 reevaluate(); 167 } 168 169 /** 170 * Sets whether the direct-reply is in use or not. 171 * @param directReplying {@code true} when the direct-reply is in-use. 172 */ setDirectReplying(boolean directReplying)173 public void setDirectReplying(boolean directReplying) { 174 if (mDirectReplying == directReplying) return; 175 mDirectReplying = directReplying; 176 reevaluate(); 177 } 178 setScrimState(ScrimState scrimState, float scrimBehindAlpha, GradientColors scrimInFrontColor)179 public void setScrimState(ScrimState scrimState, float scrimBehindAlpha, 180 GradientColors scrimInFrontColor) { 181 boolean forceDarkForScrimLast = mForceDarkForScrim; 182 // For BOUNCER/BOUNCER_SCRIMMED cases, we assume that alpha is always below threshold. 183 // This enables IMEs to control the navigation bar color. 184 // For other cases, scrim should be able to veto the light navigation bar. 185 mForceDarkForScrim = scrimState != ScrimState.BOUNCER 186 && scrimState != ScrimState.BOUNCER_SCRIMMED 187 && scrimBehindAlpha >= NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD 188 && !scrimInFrontColor.supportsDarkText(); 189 if (mHasLightNavigationBar && (mForceDarkForScrim != forceDarkForScrimLast)) { 190 reevaluate(); 191 } 192 } 193 isLight(int vis, int barMode, int flag)194 private boolean isLight(int vis, int barMode, int flag) { 195 boolean isTransparentBar = (barMode == MODE_TRANSPARENT 196 || barMode == MODE_LIGHTS_OUT_TRANSPARENT); 197 boolean light = (vis & flag) != 0; 198 return isTransparentBar && light; 199 } 200 animateChange()201 private boolean animateChange() { 202 if (mBiometricUnlockController == null) { 203 return false; 204 } 205 int unlockMode = mBiometricUnlockController.getMode(); 206 return unlockMode != BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING 207 && unlockMode != BiometricUnlockController.MODE_WAKE_AND_UNLOCK; 208 } 209 updateStatus(Rect fullscreenStackBounds, Rect dockedStackBounds)210 private void updateStatus(Rect fullscreenStackBounds, Rect dockedStackBounds) { 211 boolean hasDockedStack = !dockedStackBounds.isEmpty(); 212 213 // If both are light or fullscreen is light and there is no docked stack, all icons get 214 // dark. 215 if ((mFullscreenLight && mDockedLight) || (mFullscreenLight && !hasDockedStack)) { 216 mStatusBarIconController.setIconsDarkArea(null); 217 mStatusBarIconController.getTransitionsController().setIconsDark(true, animateChange()); 218 219 } 220 221 // If no one is light or the fullscreen is not light and there is no docked stack, 222 // all icons become white. 223 else if ((!mFullscreenLight && !mDockedLight) || (!mFullscreenLight && !hasDockedStack)) { 224 mStatusBarIconController.getTransitionsController().setIconsDark( 225 false, animateChange()); 226 } 227 228 // Not the same for every stack, magic! 229 else { 230 Rect bounds = mFullscreenLight ? fullscreenStackBounds : dockedStackBounds; 231 if (bounds.isEmpty()) { 232 mStatusBarIconController.setIconsDarkArea(null); 233 } else { 234 mStatusBarIconController.setIconsDarkArea(bounds); 235 } 236 mStatusBarIconController.getTransitionsController().setIconsDark(true, animateChange()); 237 } 238 } 239 updateNavigation()240 private void updateNavigation() { 241 if (mNavigationBarController != null) { 242 mNavigationBarController.setIconsDark( 243 mNavigationLight, animateChange()); 244 } 245 } 246 247 @Override onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging)248 public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { 249 250 } 251 252 @Override onPowerSaveChanged(boolean isPowerSave)253 public void onPowerSaveChanged(boolean isPowerSave) { 254 reevaluate(); 255 } 256 257 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)258 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 259 pw.println("LightBarController: "); 260 pw.print(" mSystemUiVisibility=0x"); pw.print( 261 Integer.toHexString(mSystemUiVisibility)); 262 pw.print(" mFullscreenStackVisibility=0x"); pw.print( 263 Integer.toHexString(mFullscreenStackVisibility)); 264 pw.print(" mDockedStackVisibility=0x"); pw.println( 265 Integer.toHexString(mDockedStackVisibility)); 266 267 pw.print(" mFullscreenLight="); pw.print(mFullscreenLight); 268 pw.print(" mDockedLight="); pw.println(mDockedLight); 269 270 pw.print(" mLastFullscreenBounds="); pw.print(mLastFullscreenBounds); 271 pw.print(" mLastDockedBounds="); pw.println(mLastDockedBounds); 272 273 pw.print(" mNavigationLight="); pw.print(mNavigationLight); 274 pw.print(" mHasLightNavigationBar="); pw.println(mHasLightNavigationBar); 275 276 pw.print(" mLastStatusBarMode="); pw.print(mLastStatusBarMode); 277 pw.print(" mLastNavigationBarMode="); pw.println(mLastNavigationBarMode); 278 279 pw.print(" mForceDarkForScrim="); pw.print(mForceDarkForScrim); 280 pw.print(" mQsCustomizing="); pw.print(mQsCustomizing); 281 pw.print(" mDirectReplying="); pw.println(mDirectReplying); 282 pw.print(" mNavbarColorManagedByIme="); pw.println(mNavbarColorManagedByIme); 283 284 pw.println(); 285 286 LightBarTransitionsController transitionsController = 287 mStatusBarIconController.getTransitionsController(); 288 if (transitionsController != null) { 289 pw.println(" StatusBarTransitionsController:"); 290 transitionsController.dump(fd, pw, args); 291 pw.println(); 292 } 293 294 if (mNavigationBarController != null) { 295 pw.println(" NavigationBarTransitionsController:"); 296 mNavigationBarController.dump(fd, pw, args); 297 pw.println(); 298 } 299 } 300 } 301