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.statusbar.phone.NavBarTintController.DEFAULT_COLOR_ADAPT_TRANSITION_TIME; 22 import static com.android.systemui.statusbar.phone.NavBarTintController.MIN_COLOR_ADAPT_TRANSITION_TIME; 23 24 import android.content.Context; 25 import android.graphics.Rect; 26 import android.os.Handler; 27 import android.os.RemoteException; 28 import android.os.ServiceManager; 29 import android.util.SparseArray; 30 import android.view.Display; 31 import android.view.IWallpaperVisibilityListener; 32 import android.view.IWindowManager; 33 import android.view.View; 34 35 import com.android.internal.statusbar.IStatusBarService; 36 import com.android.systemui.Dependency; 37 import com.android.systemui.R; 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 /** 46 * Notified when the color of nav bar elements changes. 47 */ 48 public interface DarkIntensityListener { 49 /** 50 * Called when the color of nav bar elements changes. 51 * @param darkIntensity 0 is the lightest color, 1 is the darkest. 52 */ onDarkIntensity(float darkIntensity)53 void onDarkIntensity(float darkIntensity); 54 } 55 56 private final NavigationBarView mView; 57 private final IStatusBarService mBarService; 58 private final LightBarTransitionsController mLightTransitionsController; 59 private final boolean mAllowAutoDimWallpaperNotVisible; 60 private boolean mWallpaperVisible; 61 62 private boolean mLightsOut; 63 private boolean mAutoDim; 64 private View mNavButtons; 65 private int mNavBarMode = NAV_BAR_MODE_3BUTTON; 66 private List<DarkIntensityListener> mDarkIntensityListeners; 67 68 private final Handler mHandler = Handler.getMain(); 69 private final IWallpaperVisibilityListener mWallpaperVisibilityListener = 70 new IWallpaperVisibilityListener.Stub() { 71 @Override 72 public void onWallpaperVisibilityChanged(boolean newVisibility, 73 int displayId) throws RemoteException { 74 mWallpaperVisible = newVisibility; 75 mHandler.post(() -> applyLightsOut(true, false)); 76 } 77 }; 78 NavigationBarTransitions(NavigationBarView view)79 public NavigationBarTransitions(NavigationBarView view) { 80 super(view, R.drawable.nav_background); 81 mView = view; 82 mBarService = IStatusBarService.Stub.asInterface( 83 ServiceManager.getService(Context.STATUS_BAR_SERVICE)); 84 mLightTransitionsController = new LightBarTransitionsController(view.getContext(), this); 85 mAllowAutoDimWallpaperNotVisible = view.getContext().getResources() 86 .getBoolean(R.bool.config_navigation_bar_enable_auto_dim_no_visible_wallpaper); 87 mDarkIntensityListeners = new ArrayList(); 88 89 IWindowManager windowManagerService = Dependency.get(IWindowManager.class); 90 try { 91 mWallpaperVisible = windowManagerService.registerWallpaperVisibilityListener( 92 mWallpaperVisibilityListener, Display.DEFAULT_DISPLAY); 93 } catch (RemoteException e) { 94 } 95 mView.addOnLayoutChangeListener( 96 (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { 97 View currentView = mView.getCurrentView(); 98 if (currentView != null) { 99 mNavButtons = currentView.findViewById(R.id.nav_buttons); 100 applyLightsOut(false, true); 101 } 102 }); 103 View currentView = mView.getCurrentView(); 104 if (currentView != null) { 105 mNavButtons = currentView.findViewById(R.id.nav_buttons); 106 } 107 } 108 init()109 public void init() { 110 applyModeBackground(-1, getMode(), false /*animate*/); 111 applyLightsOut(false /*animate*/, true /*force*/); 112 } 113 114 @Override destroy()115 public void destroy() { 116 IWindowManager windowManagerService = Dependency.get(IWindowManager.class); 117 try { 118 windowManagerService.unregisterWallpaperVisibilityListener(mWallpaperVisibilityListener, 119 Display.DEFAULT_DISPLAY); 120 } catch (RemoteException e) { 121 } 122 } 123 124 @Override setAutoDim(boolean autoDim)125 public void setAutoDim(boolean autoDim) { 126 // Ensure we aren't in gestural nav if we are triggering auto dim 127 if (autoDim && NavBarTintController.isEnabled(mView.getContext(), mNavBarMode)) return; 128 if (mAutoDim == autoDim) return; 129 mAutoDim = autoDim; 130 applyLightsOut(true, false); 131 } 132 setBackgroundFrame(Rect frame)133 void setBackgroundFrame(Rect frame) { 134 mBarBackground.setFrame(frame); 135 } 136 137 @Override isLightsOut(int mode)138 protected boolean isLightsOut(int mode) { 139 return super.isLightsOut(mode) || (mAllowAutoDimWallpaperNotVisible && mAutoDim 140 && !mWallpaperVisible && mode != MODE_WARNING); 141 } 142 getLightTransitionsController()143 public LightBarTransitionsController getLightTransitionsController() { 144 return mLightTransitionsController; 145 } 146 147 @Override onTransition(int oldMode, int newMode, boolean animate)148 protected void onTransition(int oldMode, int newMode, boolean animate) { 149 super.onTransition(oldMode, newMode, animate); 150 applyLightsOut(animate, false /*force*/); 151 mView.onBarTransition(newMode); 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 for (DarkIntensityListener listener : mDarkIntensityListeners) { 195 listener.onDarkIntensity(darkIntensity); 196 } 197 if (mAutoDim) { 198 applyLightsOut(false, true); 199 } 200 } 201 202 @Override getTintAnimationDuration()203 public int getTintAnimationDuration() { 204 if (NavBarTintController.isEnabled(mView.getContext(), mNavBarMode)) { 205 return Math.max(DEFAULT_COLOR_ADAPT_TRANSITION_TIME, MIN_COLOR_ADAPT_TRANSITION_TIME); 206 } 207 return LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION; 208 } 209 onNavigationModeChanged(int mode)210 public void onNavigationModeChanged(int mode) { 211 mNavBarMode = mode; 212 } 213 214 /** 215 * Register {@code listener} to be notified when the color of nav bar elements changes. 216 * 217 * Returns the current nav bar color. 218 */ addDarkIntensityListener(DarkIntensityListener listener)219 public float addDarkIntensityListener(DarkIntensityListener listener) { 220 mDarkIntensityListeners.add(listener); 221 return mLightTransitionsController.getCurrentDarkIntensity(); 222 } 223 224 /** 225 * Remove {@code listener} from being notified when the color of nav bar elements changes. 226 */ removeDarkIntensityListener(DarkIntensityListener listener)227 public void removeDarkIntensityListener(DarkIntensityListener listener) { 228 mDarkIntensityListeners.remove(listener); 229 } 230 } 231