blob: 9740d1dd6d1cb0ad33702a1da94f93a409430713 [file] [log] [blame]
Charles Chen10ca70b2018-11-28 00:03:38 +08001/*
2 * Copyright (C) 2018 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
17package com.android.systemui.statusbar;
18
19import static android.view.Display.DEFAULT_DISPLAY;
20
21import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
22
23import android.content.Context;
24import android.hardware.display.DisplayManager;
25import android.hardware.display.DisplayManager.DisplayListener;
26import android.os.Handler;
27import android.os.RemoteException;
28import android.util.Log;
29import android.util.SparseArray;
30import android.view.Display;
31import android.view.IWindowManager;
32import android.view.View;
33import android.view.WindowManagerGlobal;
34
35import com.android.systemui.Dependency;
36import com.android.systemui.plugins.DarkIconDispatcher;
Charles Chen8c9a83f2018-12-18 17:44:10 +080037import com.android.systemui.statusbar.phone.AutoHideController;
Charles Chen10ca70b2018-11-28 00:03:38 +080038import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
39import com.android.systemui.statusbar.phone.LightBarController;
40import com.android.systemui.statusbar.phone.NavigationBarFragment;
41import com.android.systemui.statusbar.phone.NavigationBarView;
42import com.android.systemui.statusbar.policy.BatteryController;
43
44import javax.inject.Inject;
45import javax.inject.Named;
46import javax.inject.Singleton;
47
48
49/** A controller to handle navigation bars. */
50@Singleton
51public class NavigationBarController implements DisplayListener {
52
53 private static final String TAG = NavigationBarController.class.getName();
54
55 private final Context mContext;
56 private final Handler mHandler;
57 private final DisplayManager mDisplayManager;
58
59 /** A displayId - nav bar maps. */
60 private SparseArray<NavigationBarFragment> mNavigationBars = new SparseArray<>();
61
62 @Inject
63 public NavigationBarController(Context context, @Named(MAIN_HANDLER_NAME) Handler handler) {
64 mContext = context;
65 mHandler = handler;
66 mDisplayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
67 mDisplayManager.registerDisplayListener(this, mHandler);
68 }
69
70 @Override
71 public void onDisplayAdded(int displayId) {
72 Display display = mDisplayManager.getDisplay(displayId);
73 createNavigationBar(display);
74 }
75
76 @Override
77 public void onDisplayRemoved(int displayId) {
78 removeNavigationBar(displayId);
79 }
80
81 @Override
82 public void onDisplayChanged(int displayId) {
83 }
84
85 // TODO(b/117478341): I use {@code includeDefaultDisplay} to make this method compatible to
86 // CarStatusBar because they have their own nav bar. Think about a better way for it.
87 /**
88 * Creates navigation bars when car/status bar initializes.
89 *
90 * @param includeDefaultDisplay {@code true} to create navigation bar on default display.
91 */
92 public void createNavigationBars(final boolean includeDefaultDisplay) {
93 Display[] displays = mDisplayManager.getDisplays();
94 for (Display display : displays) {
95 if (includeDefaultDisplay || display.getDisplayId() != DEFAULT_DISPLAY) {
96 createNavigationBar(display);
97 }
98 }
99 }
100
101 /**
102 * Adds a navigation bar on default display or an external display if the display supports
103 * system decorations.
104 *
105 * @param display the display to add navigation bar on.
106 */
107 private void createNavigationBar(Display display) {
108 if (display == null
109 || (display.getDisplayId() != DEFAULT_DISPLAY
110 && !display.supportsSystemDecorations())) {
111 return;
112 }
113
114 final int displayId = display.getDisplayId();
115 final boolean isOnDefaultDisplay = displayId == DEFAULT_DISPLAY;
116 final IWindowManager wms = WindowManagerGlobal.getWindowManagerService();
117
118 try {
119 if (!wms.hasNavigationBar(displayId)) {
120 return;
121 }
122 } catch (RemoteException e) {
123 // Cannot get wms, just return with warning message.
124 Log.w(TAG, "Cannot get WindowManager.");
125 return;
126 }
127 final Context context = isOnDefaultDisplay
128 ? mContext
129 : mContext.createDisplayContext(display);
130 NavigationBarFragment.create(context, (tag, fragment) -> {
131 NavigationBarFragment navBar = (NavigationBarFragment) fragment;
132
133 // Unfortunately, we still need it because status bar needs LightBarController
134 // before notifications creation. We cannot directly use getLightBarController()
135 // from NavigationBarFragment directly.
Charles Chen8c9a83f2018-12-18 17:44:10 +0800136 LightBarController lightBarController = isOnDefaultDisplay
Charles Chen10ca70b2018-11-28 00:03:38 +0800137 ? Dependency.get(LightBarController.class)
138 : new LightBarController(context,
139 Dependency.get(DarkIconDispatcher.class),
140 Dependency.get(BatteryController.class));
Charles Chen8c9a83f2018-12-18 17:44:10 +0800141 navBar.setLightBarController(lightBarController);
142
143 // TODO(b/118592525): to support multi-display, we start to add something which is
144 // per-display, while others may be global. I think it's time to add
145 // a new class maybe named DisplayDependency to solve per-display
146 // Dependency problem.
147 AutoHideController autoHideController = isOnDefaultDisplay
148 ? Dependency.get(AutoHideController.class)
149 : new AutoHideController(context, mHandler);
150 navBar.setAutoHideController(autoHideController);
Charles Chen10ca70b2018-11-28 00:03:38 +0800151 navBar.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
152 mNavigationBars.append(displayId, navBar);
153 });
154 }
155
156 /** Removes navigation bars. */
157 public void destroy() {
158 mDisplayManager.unregisterDisplayListener(this);
159 if (mNavigationBars.size() > 0) {
160 for (int i = 0; i < mNavigationBars.size(); i++) {
161 int displayId = mNavigationBars.keyAt(i);
162 removeNavigationBar(displayId);
163 }
164 mNavigationBars.clear();
165 }
166 }
167
168 private void removeNavigationBar(int displayId) {
169 NavigationBarFragment navBar = mNavigationBars.get(displayId);
170 if (navBar != null) {
171 View navigationWindow = navBar.getView().getRootView();
172 WindowManagerGlobal.getInstance()
173 .removeView(navigationWindow, true /* immediate */);
174 mNavigationBars.remove(displayId);
175 }
176 }
177
178 /** @see NavigationBarFragment#checkNavBarModes() */
179 public void checkNavBarModes(int displayId) {
180 NavigationBarFragment navBar = mNavigationBars.get(displayId);
181 if (navBar != null) {
182 navBar.checkNavBarModes();
183 }
184 }
185
186 /** @see NavigationBarFragment#finishBarAnimations() */
187 public void finishBarAnimations(int displayId) {
188 NavigationBarFragment navBar = mNavigationBars.get(displayId);
189 if (navBar != null) {
190 navBar.finishBarAnimations();
191 }
192 }
193
194 /** @see NavigationBarFragment#touchAutoDim() */
195 public void touchAutoDim(int displayId) {
196 NavigationBarFragment navBar = mNavigationBars.get(displayId);
197 if (navBar != null) {
198 navBar.touchAutoDim();
199 }
200 }
201
202 /** @see NavigationBarFragment#transitionTo(int, boolean) */
203 public void transitionTo(int displayId, @TransitionMode int barMode, boolean animate) {
204 NavigationBarFragment navBar = mNavigationBars.get(displayId);
205 if (navBar != null) {
206 navBar.transitionTo(barMode, animate);
207 }
208 }
209
Charles Chen10ca70b2018-11-28 00:03:38 +0800210 /** @see NavigationBarFragment#disableAnimationsDuringHide(long) */
211 public void disableAnimationsDuringHide(int displayId, long delay) {
212 NavigationBarFragment navBar = mNavigationBars.get(displayId);
213 if (navBar != null) {
214 navBar.disableAnimationsDuringHide(delay);
215 }
216 }
217
218 /** @return {@link NavigationBarView} on the default display. */
219 public NavigationBarView getDefaultNavigationBarView() {
220 NavigationBarFragment navBar = mNavigationBars.get(DEFAULT_DISPLAY);
221 return (navBar == null) ? null : (NavigationBarView) navBar.getView();
222 }
223}