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 17package com.android.systemui.statusbar.phone; 18 19import android.graphics.Rect; 20import android.view.View; 21 22import com.android.systemui.Dependency; 23import com.android.systemui.Dumpable; 24import com.android.systemui.statusbar.policy.BatteryController; 25import com.android.systemui.statusbar.policy.DarkIconDispatcher; 26 27import java.io.FileDescriptor; 28import java.io.PrintWriter; 29 30import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT; 31import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT; 32 33/** 34 * Controls how light status bar flag applies to the icons. 35 */ 36public 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 69 public LightBarController() { 70 mStatusBarIconController = Dependency.get(DarkIconDispatcher.class); 71 mBatteryController = Dependency.get(BatteryController.class); 72 mBatteryController.addCallback(this); 73 } 74 75 public void setNavigationBar(LightBarTransitionsController navigationBar) { 76 mNavigationBarController = navigationBar; 77 } 78 79 public void setFingerprintUnlockController( 80 FingerprintUnlockController fingerprintUnlockController) { 81 mFingerprintUnlockController = fingerprintUnlockController; 82 } 83 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 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 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 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