1 /* 2 * Copyright (C) 2020 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.navigationbar; 18 19 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; 20 21 import static com.android.systemui.util.Utils.isGesturalModeOnDefaultDisplay; 22 23 import android.graphics.Rect; 24 import android.util.SparseArray; 25 import android.view.View; 26 27 import com.android.systemui.navigationbar.NavigationBarComponent.NavigationBarScope; 28 import com.android.systemui.navigationbar.buttons.ButtonDispatcher; 29 import com.android.systemui.res.R; 30 import com.android.systemui.settings.DisplayTracker; 31 import com.android.systemui.statusbar.phone.BarTransitions; 32 import com.android.systemui.statusbar.phone.LightBarTransitionsController; 33 34 import java.io.PrintWriter; 35 import java.util.ArrayList; 36 import java.util.List; 37 38 import javax.inject.Inject; 39 40 /** */ 41 @NavigationBarScope 42 public final class NavigationBarTransitions extends BarTransitions implements 43 LightBarTransitionsController.DarkIntensityApplier { 44 45 public static final int MIN_COLOR_ADAPT_TRANSITION_TIME = 400; 46 public static final int DEFAULT_COLOR_ADAPT_TRANSITION_TIME = 1700; 47 private List<Listener> mListeners = new ArrayList<>(); 48 49 /** 50 * Notified when the color of nav bar elements changes. 51 */ 52 public interface DarkIntensityListener { 53 /** 54 * Called when the color of nav bar elements changes. 55 * @param darkIntensity 0 is the lightest color, 1 is the darkest. 56 */ onDarkIntensity(float darkIntensity)57 void onDarkIntensity(float darkIntensity); 58 } 59 60 private final NavigationBarView mView; 61 private final LightBarTransitionsController mLightTransitionsController; 62 private final DisplayTracker mDisplayTracker; 63 private final boolean mAllowAutoDimWallpaperNotVisible; 64 private boolean mWallpaperVisible; 65 66 private boolean mLightsOut; 67 private boolean mAutoDim; 68 private View mNavButtons; 69 private int mNavBarMode = NAV_BAR_MODE_3BUTTON; 70 private List<DarkIntensityListener> mDarkIntensityListeners; 71 72 @Inject NavigationBarTransitions( NavigationBarView view, LightBarTransitionsController.Factory lightBarTransitionsControllerFactory, DisplayTracker displayTracker)73 public NavigationBarTransitions( 74 NavigationBarView view, 75 LightBarTransitionsController.Factory lightBarTransitionsControllerFactory, 76 DisplayTracker displayTracker) { 77 super(view, R.drawable.nav_background); 78 79 mView = view; 80 mLightTransitionsController = lightBarTransitionsControllerFactory.create(this); 81 mDisplayTracker = displayTracker; 82 mAllowAutoDimWallpaperNotVisible = view.getContext().getResources() 83 .getBoolean(R.bool.config_navigation_bar_enable_auto_dim_no_visible_wallpaper); 84 mDarkIntensityListeners = new ArrayList(); 85 86 mView.addOnLayoutChangeListener( 87 (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { 88 View currentView = mView.getCurrentView(); 89 if (currentView != null) { 90 mNavButtons = currentView.findViewById(R.id.nav_buttons); 91 applyLightsOut(false, true); 92 } 93 }); 94 View currentView = mView.getCurrentView(); 95 if (currentView != null) { 96 mNavButtons = currentView.findViewById(R.id.nav_buttons); 97 } 98 } 99 init()100 public void init() { 101 applyModeBackground(-1, getMode(), false /*animate*/); 102 applyLightsOut(false /*animate*/, true /*force*/); 103 } 104 105 @Override destroy()106 public void destroy() { 107 mLightTransitionsController.destroy(); 108 } 109 setWallpaperVisibility(boolean visible)110 void setWallpaperVisibility(boolean visible) { 111 mWallpaperVisible = visible; 112 applyLightsOut(true, false); 113 } 114 115 @Override setAutoDim(boolean autoDim)116 public void setAutoDim(boolean autoDim) { 117 // Ensure we aren't in gestural nav if we are triggering auto dim 118 if (autoDim && isGesturalModeOnDefaultDisplay(mView.getContext(), mDisplayTracker, 119 mNavBarMode)) { 120 return; 121 } 122 if (mAutoDim == autoDim) return; 123 mAutoDim = autoDim; 124 applyLightsOut(true, false); 125 } 126 setBackgroundFrame(Rect frame)127 void setBackgroundFrame(Rect frame) { 128 mBarBackground.setFrame(frame); 129 } 130 setBackgroundOverrideAlpha(float alpha)131 void setBackgroundOverrideAlpha(float alpha) { 132 mBarBackground.setOverrideAlpha(alpha); 133 } 134 135 @Override isLightsOut(int mode)136 protected boolean isLightsOut(int mode) { 137 return super.isLightsOut(mode) || (mAllowAutoDimWallpaperNotVisible && mAutoDim 138 && !mWallpaperVisible && mode != MODE_WARNING); 139 } 140 getLightTransitionsController()141 public LightBarTransitionsController getLightTransitionsController() { 142 return mLightTransitionsController; 143 } 144 145 @Override onTransition(int oldMode, int newMode, boolean animate)146 protected void onTransition(int oldMode, int newMode, boolean animate) { 147 super.onTransition(oldMode, newMode, animate); 148 applyLightsOut(animate, false /*force*/); 149 for (Listener listener : mListeners) { 150 listener.onTransition(newMode); 151 } 152 } 153 applyLightsOut(boolean animate, boolean force)154 private void applyLightsOut(boolean animate, boolean force) { 155 // apply to lights out 156 applyLightsOut(isLightsOut(getMode()), animate, force); 157 } 158 applyLightsOut(boolean lightsOut, boolean animate, boolean force)159 private void applyLightsOut(boolean lightsOut, boolean animate, boolean force) { 160 if (!force && lightsOut == mLightsOut) return; 161 162 mLightsOut = lightsOut; 163 if (mNavButtons == null) return; 164 165 // ok, everyone, stop it right there 166 mNavButtons.animate().cancel(); 167 168 // Bump percentage by 10% if dark. 169 float darkBump = mLightTransitionsController.getCurrentDarkIntensity() / 10; 170 final float navButtonsAlpha = lightsOut ? 0.6f + darkBump : 1f; 171 172 if (!animate) { 173 mNavButtons.setAlpha(navButtonsAlpha); 174 } else { 175 final int duration = lightsOut ? LIGHTS_OUT_DURATION : LIGHTS_IN_DURATION; 176 mNavButtons.animate() 177 .alpha(navButtonsAlpha) 178 .setDuration(duration) 179 .start(); 180 } 181 } 182 reapplyDarkIntensity()183 public void reapplyDarkIntensity() { 184 applyDarkIntensity(mLightTransitionsController.getCurrentDarkIntensity()); 185 } 186 187 @Override applyDarkIntensity(float darkIntensity)188 public void applyDarkIntensity(float darkIntensity) { 189 SparseArray<ButtonDispatcher> buttonDispatchers = mView.getButtonDispatchers(); 190 for (int i = buttonDispatchers.size() - 1; i >= 0; i--) { 191 buttonDispatchers.valueAt(i).setDarkIntensity(darkIntensity); 192 } 193 mView.getRotationButtonController().setDarkIntensity(darkIntensity); 194 195 for (DarkIntensityListener listener : mDarkIntensityListeners) { 196 listener.onDarkIntensity(darkIntensity); 197 } 198 if (mAutoDim) { 199 applyLightsOut(false, true); 200 } 201 } 202 203 @Override getTintAnimationDuration()204 public int getTintAnimationDuration() { 205 if (isGesturalModeOnDefaultDisplay(mView.getContext(), mDisplayTracker, mNavBarMode)) { 206 return Math.max(DEFAULT_COLOR_ADAPT_TRANSITION_TIME, MIN_COLOR_ADAPT_TRANSITION_TIME); 207 } 208 return LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION; 209 } 210 onNavigationModeChanged(int mode)211 public void onNavigationModeChanged(int mode) { 212 mNavBarMode = mode; 213 } 214 215 /** 216 * Register {@code listener} to be notified when the color of nav bar elements changes. 217 * 218 * Returns the current nav bar color. 219 */ addDarkIntensityListener(DarkIntensityListener listener)220 public float addDarkIntensityListener(DarkIntensityListener listener) { 221 mDarkIntensityListeners.add(listener); 222 return mLightTransitionsController.getCurrentDarkIntensity(); 223 } 224 225 /** 226 * Remove {@code listener} from being notified when the color of nav bar elements changes. 227 */ removeDarkIntensityListener(DarkIntensityListener listener)228 public void removeDarkIntensityListener(DarkIntensityListener listener) { 229 mDarkIntensityListeners.remove(listener); 230 } 231 dump(PrintWriter pw)232 public void dump(PrintWriter pw) { 233 pw.println("NavigationBarTransitions:"); 234 pw.println(" mMode: " + getMode()); 235 pw.println(" mAlwaysOpaque: " + isAlwaysOpaque()); 236 pw.println(" mAllowAutoDimWallpaperNotVisible: " + mAllowAutoDimWallpaperNotVisible); 237 pw.println(" mWallpaperVisible: " + mWallpaperVisible); 238 pw.println(" mLightsOut: " + mLightsOut); 239 pw.println(" mAutoDim: " + mAutoDim); 240 pw.println(" bg overrideAlpha: " + mBarBackground.getOverrideAlpha()); 241 pw.println(" bg color: " + mBarBackground.getColor()); 242 pw.println(" bg frame: " + mBarBackground.getFrame()); 243 } 244 addListener(Listener listener)245 void addListener(Listener listener) { 246 mListeners.add(listener); 247 } 248 removeListener(Listener listener)249 void removeListener(Listener listener) { 250 mListeners.remove(listener); 251 } 252 253 interface Listener { onTransition(int newMode)254 void onTransition(int newMode); 255 } 256 } 257