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