blob: 262cf2a287e9c8e53442d78d21373ef46baf8bf7 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.systemui.statusbar.phone;
import android.app.WallpaperColors;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Rect;
import android.view.View;
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
/**
* Controls how light status bar flag applies to the icons.
*/
public class LightBarController implements BatteryController.BatteryStateChangeCallback, Dumpable {
private static final float NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD = 0.1f;
private final DarkIconDispatcher mStatusBarIconController;
private final BatteryController mBatteryController;
private BiometricUnlockController mBiometricUnlockController;
private LightBarTransitionsController mNavigationBarController;
private int mSystemUiVisibility;
private int mFullscreenStackVisibility;
private int mDockedStackVisibility;
private boolean mFullscreenLight;
private boolean mDockedLight;
private int mLastStatusBarMode;
private int mLastNavigationBarMode;
private final Color mDarkModeColor;
/**
* Whether the navigation bar should be light factoring in already how much alpha the scrim has
*/
private boolean mNavigationLight;
/**
* Whether the flags indicate that a light status bar is requested. This doesn't factor in the
* scrim alpha yet.
*/
private boolean mHasLightNavigationBar;
private boolean mScrimAlphaBelowThreshold;
private boolean mInvertLightNavBarWithScrim;
private float mScrimAlpha;
private final Rect mLastFullscreenBounds = new Rect();
private final Rect mLastDockedBounds = new Rect();
private boolean mQsCustomizing;
public LightBarController(Context ctx) {
mDarkModeColor = Color.valueOf(ctx.getColor(R.color.dark_mode_icon_color_single_tone));
mStatusBarIconController = Dependency.get(DarkIconDispatcher.class);
mBatteryController = Dependency.get(BatteryController.class);
mBatteryController.addCallback(this);
}
public void setNavigationBar(LightBarTransitionsController navigationBar) {
mNavigationBarController = navigationBar;
updateNavigation();
}
public void setBiometricUnlockController(
BiometricUnlockController biometricUnlockController) {
mBiometricUnlockController = biometricUnlockController;
}
public void onSystemUiVisibilityChanged(int fullscreenStackVis, int dockedStackVis,
int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, boolean sbModeChanged,
int statusBarMode) {
int oldFullscreen = mFullscreenStackVisibility;
int newFullscreen = (oldFullscreen & ~mask) | (fullscreenStackVis & mask);
int diffFullscreen = newFullscreen ^ oldFullscreen;
int oldDocked = mDockedStackVisibility;
int newDocked = (oldDocked & ~mask) | (dockedStackVis & mask);
int diffDocked = newDocked ^ oldDocked;
if ((diffFullscreen & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0
|| (diffDocked & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0
|| sbModeChanged
|| !mLastFullscreenBounds.equals(fullscreenStackBounds)
|| !mLastDockedBounds.equals(dockedStackBounds)) {
mFullscreenLight = isLight(newFullscreen, statusBarMode,
View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
mDockedLight = isLight(newDocked, statusBarMode, View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
updateStatus(fullscreenStackBounds, dockedStackBounds);
}
mFullscreenStackVisibility = newFullscreen;
mDockedStackVisibility = newDocked;
mLastStatusBarMode = statusBarMode;
mLastFullscreenBounds.set(fullscreenStackBounds);
mLastDockedBounds.set(dockedStackBounds);
}
public void onNavigationVisibilityChanged(int vis, int mask, boolean nbModeChanged,
int navigationBarMode) {
int oldVis = mSystemUiVisibility;
int newVis = (oldVis & ~mask) | (vis & mask);
int diffVis = newVis ^ oldVis;
if ((diffVis & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0
|| nbModeChanged) {
boolean last = mNavigationLight;
mHasLightNavigationBar = isLight(vis, navigationBarMode,
View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
mNavigationLight = mHasLightNavigationBar
&& (mScrimAlphaBelowThreshold || !mInvertLightNavBarWithScrim)
&& !mQsCustomizing;
if (mNavigationLight != last) {
updateNavigation();
}
}
mSystemUiVisibility = newVis;
mLastNavigationBarMode = navigationBarMode;
}
private void reevaluate() {
onSystemUiVisibilityChanged(mFullscreenStackVisibility,
mDockedStackVisibility, 0 /* mask */, mLastFullscreenBounds, mLastDockedBounds,
true /* sbModeChange*/, mLastStatusBarMode);
onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */, true /* nbModeChanged */,
mLastNavigationBarMode);
}
public void setQsCustomizing(boolean customizing) {
if (mQsCustomizing == customizing) return;
mQsCustomizing = customizing;
reevaluate();
}
public void setScrimAlpha(float alpha) {
mScrimAlpha = alpha;
boolean belowThresholdBefore = mScrimAlphaBelowThreshold;
mScrimAlphaBelowThreshold = mScrimAlpha < NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD;
if (mHasLightNavigationBar && belowThresholdBefore != mScrimAlphaBelowThreshold) {
reevaluate();
}
}
public void setScrimColor(GradientColors colors) {
boolean invertLightNavBarWithScrimBefore = mInvertLightNavBarWithScrim;
mInvertLightNavBarWithScrim = !colors.supportsDarkText();
if (mHasLightNavigationBar
&& invertLightNavBarWithScrimBefore != mInvertLightNavBarWithScrim) {
reevaluate();
}
}
private boolean isLight(int vis, int barMode, int flag) {
boolean isTransparentBar = (barMode == MODE_TRANSPARENT
|| barMode == MODE_LIGHTS_OUT_TRANSPARENT);
boolean allowLight = isTransparentBar && !mBatteryController.isPowerSave();
boolean light = (vis & flag) != 0;
return allowLight && light;
}
private boolean animateChange() {
if (mBiometricUnlockController == null) {
return false;
}
int unlockMode = mBiometricUnlockController.getMode();
return unlockMode != BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
&& unlockMode != BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
}
private void updateStatus(Rect fullscreenStackBounds, Rect dockedStackBounds) {
boolean hasDockedStack = !dockedStackBounds.isEmpty();
// If both are light or fullscreen is light and there is no docked stack, all icons get
// dark.
if ((mFullscreenLight && mDockedLight) || (mFullscreenLight && !hasDockedStack)) {
mStatusBarIconController.setIconsDarkArea(null);
mStatusBarIconController.getTransitionsController().setIconsDark(true, animateChange());
}
// If no one is light or the fullscreen is not light and there is no docked stack,
// all icons become white.
else if ((!mFullscreenLight && !mDockedLight) || (!mFullscreenLight && !hasDockedStack)) {
mStatusBarIconController.getTransitionsController().setIconsDark(
false, animateChange());
}
// Not the same for every stack, magic!
else {
Rect bounds = mFullscreenLight ? fullscreenStackBounds : dockedStackBounds;
if (bounds.isEmpty()) {
mStatusBarIconController.setIconsDarkArea(null);
} else {
mStatusBarIconController.setIconsDarkArea(bounds);
}
mStatusBarIconController.getTransitionsController().setIconsDark(true, animateChange());
}
}
private void updateNavigation() {
if (mNavigationBarController != null) {
mNavigationBarController.setIconsDark(
mNavigationLight, animateChange());
}
}
@Override
public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
}
@Override
public void onPowerSaveChanged(boolean isPowerSave) {
reevaluate();
}
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("LightBarController: ");
pw.print(" mSystemUiVisibility=0x"); pw.print(
Integer.toHexString(mSystemUiVisibility));
pw.print(" mFullscreenStackVisibility=0x"); pw.print(
Integer.toHexString(mFullscreenStackVisibility));
pw.print(" mDockedStackVisibility=0x"); pw.println(
Integer.toHexString(mDockedStackVisibility));
pw.print(" mFullscreenLight="); pw.print(mFullscreenLight);
pw.print(" mDockedLight="); pw.println(mDockedLight);
pw.print(" mLastFullscreenBounds="); pw.print(mLastFullscreenBounds);
pw.print(" mLastDockedBounds="); pw.println(mLastDockedBounds);
pw.print(" mNavigationLight="); pw.print(mNavigationLight);
pw.print(" mHasLightNavigationBar="); pw.println(mHasLightNavigationBar);
pw.print(" mLastStatusBarMode="); pw.print(mLastStatusBarMode);
pw.print(" mLastNavigationBarMode="); pw.println(mLastNavigationBarMode);
pw.print(" mScrimAlpha="); pw.print(mScrimAlpha);
pw.print(" mScrimAlphaBelowThreshold="); pw.println(mScrimAlphaBelowThreshold);
pw.println();
pw.println(" StatusBarTransitionsController:");
mStatusBarIconController.getTransitionsController().dump(fd, pw, args);
pw.println();
pw.println(" NavigationBarTransitionsController:");
if (mNavigationBarController != null) {
mNavigationBarController.dump(fd, pw, args);
}
pw.println();
}
}