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