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 android.content.Context;
20 import android.os.Handler;
21 import android.os.RemoteException;
22 import android.os.ServiceManager;
23 import android.util.SparseArray;
24 import android.view.Display;
25 import android.view.IWallpaperVisibilityListener;
26 import android.view.IWindowManager;
27 import android.view.MotionEvent;
28 import android.view.View;
29 import android.view.View.OnLayoutChangeListener;
30 
31 import com.android.internal.statusbar.IStatusBarService;
32 import com.android.systemui.Dependency;
33 import com.android.systemui.R;
34 
35 public final class NavigationBarTransitions extends BarTransitions {
36 
37     private final NavigationBarView mView;
38     private final IStatusBarService mBarService;
39     private final LightBarTransitionsController mLightTransitionsController;
40     private final boolean mAllowAutoDimWallpaperNotVisible;
41     private boolean mWallpaperVisible;
42 
43     private boolean mLightsOut;
44     private boolean mAutoDim;
45     private View mNavButtons;
46 
NavigationBarTransitions(NavigationBarView view)47     public NavigationBarTransitions(NavigationBarView view) {
48         super(view, R.drawable.nav_background);
49         mView = view;
50         mBarService = IStatusBarService.Stub.asInterface(
51                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
52         mLightTransitionsController = new LightBarTransitionsController(view.getContext(),
53                 this::applyDarkIntensity);
54         mAllowAutoDimWallpaperNotVisible = view.getContext().getResources()
55                 .getBoolean(R.bool.config_navigation_bar_enable_auto_dim_no_visible_wallpaper);
56 
57         IWindowManager windowManagerService = Dependency.get(IWindowManager.class);
58         Handler handler = Handler.getMain();
59         try {
60             mWallpaperVisible = windowManagerService.registerWallpaperVisibilityListener(
61                 new IWallpaperVisibilityListener.Stub() {
62                     @Override
63                     public void onWallpaperVisibilityChanged(boolean newVisibility,
64                             int displayId) throws RemoteException {
65                         mWallpaperVisible = newVisibility;
66                         handler.post(() -> applyLightsOut(true, false));
67                     }
68                 }, Display.DEFAULT_DISPLAY);
69         } catch (RemoteException e) {
70         }
71         mView.addOnLayoutChangeListener(
72                 (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
73                     View currentView = mView.getCurrentView();
74                     if (currentView != null) {
75                         mNavButtons = currentView.findViewById(R.id.nav_buttons);
76                         applyLightsOut(false, true);
77                     }
78                 });
79         View currentView = mView.getCurrentView();
80         if (currentView != null) {
81             mNavButtons = currentView.findViewById(R.id.nav_buttons);
82         }
83     }
84 
init()85     public void init() {
86         applyModeBackground(-1, getMode(), false /*animate*/);
87         applyLightsOut(false /*animate*/, true /*force*/);
88     }
89 
90     @Override
setAutoDim(boolean autoDim)91     public void setAutoDim(boolean autoDim) {
92         if (mAutoDim == autoDim) return;
93         mAutoDim = autoDim;
94         applyLightsOut(true, false);
95     }
96 
97     @Override
isLightsOut(int mode)98     protected boolean isLightsOut(int mode) {
99         return super.isLightsOut(mode) || (mAllowAutoDimWallpaperNotVisible && mAutoDim
100                 && !mWallpaperVisible && mode != MODE_WARNING);
101     }
102 
getLightTransitionsController()103     public LightBarTransitionsController getLightTransitionsController() {
104         return mLightTransitionsController;
105     }
106 
107     @Override
onTransition(int oldMode, int newMode, boolean animate)108     protected void onTransition(int oldMode, int newMode, boolean animate) {
109         super.onTransition(oldMode, newMode, animate);
110         applyLightsOut(animate, false /*force*/);
111     }
112 
applyLightsOut(boolean animate, boolean force)113     private void applyLightsOut(boolean animate, boolean force) {
114         // apply to lights out
115         applyLightsOut(isLightsOut(getMode()), animate, force);
116     }
117 
applyLightsOut(boolean lightsOut, boolean animate, boolean force)118     private void applyLightsOut(boolean lightsOut, boolean animate, boolean force) {
119         if (!force && lightsOut == mLightsOut) return;
120 
121         mLightsOut = lightsOut;
122         if (mNavButtons == null) return;
123 
124         // ok, everyone, stop it right there
125         mNavButtons.animate().cancel();
126 
127         // Bump percentage by 10% if dark.
128         float darkBump = mLightTransitionsController.getCurrentDarkIntensity() / 10;
129         final float navButtonsAlpha = lightsOut ? 0.6f + darkBump : 1f;
130 
131         if (!animate) {
132             mNavButtons.setAlpha(navButtonsAlpha);
133         } else {
134             final int duration = lightsOut ? LIGHTS_OUT_DURATION : LIGHTS_IN_DURATION;
135             mNavButtons.animate()
136                 .alpha(navButtonsAlpha)
137                 .setDuration(duration)
138                 .start();
139         }
140     }
141 
reapplyDarkIntensity()142     public void reapplyDarkIntensity() {
143         applyDarkIntensity(mLightTransitionsController.getCurrentDarkIntensity());
144     }
145 
applyDarkIntensity(float darkIntensity)146     public void applyDarkIntensity(float darkIntensity) {
147         SparseArray<ButtonDispatcher> buttonDispatchers = mView.getButtonDispatchers();
148         for (int i = buttonDispatchers.size() - 1; i >= 0; i--) {
149             buttonDispatchers.valueAt(i).setDarkIntensity(darkIntensity);
150         }
151         if (mAutoDim) {
152             applyLightsOut(false, true);
153         }
154         mView.onDarkIntensityChange(darkIntensity);
155     }
156 
157     private final View.OnTouchListener mLightsOutListener = new View.OnTouchListener() {
158         @Override
159         public boolean onTouch(View v, MotionEvent ev) {
160             if (ev.getAction() == MotionEvent.ACTION_DOWN) {
161                 // even though setting the systemUI visibility below will turn these views
162                 // on, we need them to come up faster so that they can catch this motion
163                 // event
164                 applyLightsOut(false, false, false);
165 
166                 try {
167                     mBarService.setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE,
168                             "LightsOutListener");
169                 } catch (android.os.RemoteException ex) {
170                 }
171             }
172             return false;
173         }
174     };
175 }
176