1 /* 2 * Copyright (C) 2013 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 android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; 20 21 import static com.android.systemui.util.Utils.isGesturalModeOnDefaultDisplay; 22 23 import android.content.Context; 24 import android.graphics.Rect; 25 import android.os.Handler; 26 import android.os.RemoteException; 27 import android.os.ServiceManager; 28 import android.util.SparseArray; 29 import android.view.Display; 30 import android.view.IWallpaperVisibilityListener; 31 import android.view.IWindowManager; 32 import android.view.View; 33 34 import com.android.internal.statusbar.IStatusBarService; 35 import com.android.systemui.Dependency; 36 import com.android.systemui.R; 37 import com.android.systemui.statusbar.CommandQueue; 38 39 import java.util.ArrayList; 40 import java.util.List; 41 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 48 /** 49 * Notified when the color of nav bar elements changes. 50 */ 51 public interface DarkIntensityListener { 52 /** 53 * Called when the color of nav bar elements changes. 54 * @param darkIntensity 0 is the lightest color, 1 is the darkest. 55 */ onDarkIntensity(float darkIntensity)56 void onDarkIntensity(float darkIntensity); 57 } 58 59 private final NavigationBarView mView; 60 private final LightBarTransitionsController mLightTransitionsController; 61 private final boolean mAllowAutoDimWallpaperNotVisible; 62 private boolean mWallpaperVisible; 63 64 private boolean mLightsOut; 65 private boolean mAutoDim; 66 private View mNavButtons; 67 private int mNavBarMode = NAV_BAR_MODE_3BUTTON; 68 private List<DarkIntensityListener> mDarkIntensityListeners; 69 70 private final Handler mHandler = Handler.getMain(); 71 private final IWallpaperVisibilityListener mWallpaperVisibilityListener = 72 new IWallpaperVisibilityListener.Stub() { 73 @Override 74 public void onWallpaperVisibilityChanged(boolean newVisibility, 75 int displayId) throws RemoteException { 76 mWallpaperVisible = newVisibility; 77 mHandler.post(() -> applyLightsOut(true, false)); 78 } 79 }; 80 NavigationBarTransitions(NavigationBarView view, CommandQueue commandQueue)81 public NavigationBarTransitions(NavigationBarView view, CommandQueue commandQueue) { 82 super(view, R.drawable.nav_background); 83 mView = view; 84 mLightTransitionsController = new LightBarTransitionsController( 85 view.getContext(), this, commandQueue); 86 mAllowAutoDimWallpaperNotVisible = view.getContext().getResources() 87 .getBoolean(R.bool.config_navigation_bar_enable_auto_dim_no_visible_wallpaper); 88 mDarkIntensityListeners = new ArrayList(); 89 90 IWindowManager windowManagerService = Dependency.get(IWindowManager.class); 91 try { 92 mWallpaperVisible = windowManagerService.registerWallpaperVisibilityListener( 93 mWallpaperVisibilityListener, Display.DEFAULT_DISPLAY); 94 } catch (RemoteException e) { 95 } 96 mView.addOnLayoutChangeListener( 97 (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { 98 View currentView = mView.getCurrentView(); 99 if (currentView != null) { 100 mNavButtons = currentView.findViewById(R.id.nav_buttons); 101 applyLightsOut(false, true); 102 } 103 }); 104 View currentView = mView.getCurrentView(); 105 if (currentView != null) { 106 mNavButtons = currentView.findViewById(R.id.nav_buttons); 107 } 108 } 109 init()110 public void init() { 111 applyModeBackground(-1, getMode(), false /*animate*/); 112 applyLightsOut(false /*animate*/, true /*force*/); 113 } 114 115 @Override destroy()116 public void destroy() { 117 IWindowManager windowManagerService = Dependency.get(IWindowManager.class); 118 try { 119 windowManagerService.unregisterWallpaperVisibilityListener(mWallpaperVisibilityListener, 120 Display.DEFAULT_DISPLAY); 121 } catch (RemoteException e) { 122 } 123 } 124 125 @Override setAutoDim(boolean autoDim)126 public void setAutoDim(boolean autoDim) { 127 // Ensure we aren't in gestural nav if we are triggering auto dim 128 if (autoDim && isGesturalModeOnDefaultDisplay(mView.getContext(), mNavBarMode)) return; 129 if (mAutoDim == autoDim) return; 130 mAutoDim = autoDim; 131 applyLightsOut(true, false); 132 } 133 setBackgroundFrame(Rect frame)134 void setBackgroundFrame(Rect frame) { 135 mBarBackground.setFrame(frame); 136 } 137 138 @Override isLightsOut(int mode)139 protected boolean isLightsOut(int mode) { 140 return super.isLightsOut(mode) || (mAllowAutoDimWallpaperNotVisible && mAutoDim 141 && !mWallpaperVisible && mode != MODE_WARNING); 142 } 143 getLightTransitionsController()144 public LightBarTransitionsController getLightTransitionsController() { 145 return mLightTransitionsController; 146 } 147 148 @Override onTransition(int oldMode, int newMode, boolean animate)149 protected void onTransition(int oldMode, int newMode, boolean animate) { 150 super.onTransition(oldMode, newMode, animate); 151 applyLightsOut(animate, false /*force*/); 152 mView.onBarTransition(newMode); 153 } 154 applyLightsOut(boolean animate, boolean force)155 private void applyLightsOut(boolean animate, boolean force) { 156 // apply to lights out 157 applyLightsOut(isLightsOut(getMode()), animate, force); 158 } 159 applyLightsOut(boolean lightsOut, boolean animate, boolean force)160 private void applyLightsOut(boolean lightsOut, boolean animate, boolean force) { 161 if (!force && lightsOut == mLightsOut) return; 162 163 mLightsOut = lightsOut; 164 if (mNavButtons == null) return; 165 166 // ok, everyone, stop it right there 167 mNavButtons.animate().cancel(); 168 169 // Bump percentage by 10% if dark. 170 float darkBump = mLightTransitionsController.getCurrentDarkIntensity() / 10; 171 final float navButtonsAlpha = lightsOut ? 0.6f + darkBump : 1f; 172 173 if (!animate) { 174 mNavButtons.setAlpha(navButtonsAlpha); 175 } else { 176 final int duration = lightsOut ? LIGHTS_OUT_DURATION : LIGHTS_IN_DURATION; 177 mNavButtons.animate() 178 .alpha(navButtonsAlpha) 179 .setDuration(duration) 180 .start(); 181 } 182 } 183 reapplyDarkIntensity()184 public void reapplyDarkIntensity() { 185 applyDarkIntensity(mLightTransitionsController.getCurrentDarkIntensity()); 186 } 187 188 @Override applyDarkIntensity(float darkIntensity)189 public void applyDarkIntensity(float darkIntensity) { 190 SparseArray<ButtonDispatcher> buttonDispatchers = mView.getButtonDispatchers(); 191 for (int i = buttonDispatchers.size() - 1; i >= 0; i--) { 192 buttonDispatchers.valueAt(i).setDarkIntensity(darkIntensity); 193 } 194 mView.getRotationButtonController().setDarkIntensity(darkIntensity); 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(), 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 } 232