blob: 1f389049f4230692cefd1684257a6b094f987459 [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
Charles Chen3dedec32019-01-24 22:19:37 +080021import static com.android.systemui.SysUiServiceProvider.getComponent;
Charles Chen10ca70b2018-11-28 00:03:38 +080022
23import android.content.Context;
24import android.hardware.display.DisplayManager;
Charles Chen10ca70b2018-11-28 00:03:38 +080025import android.os.Handler;
26import android.os.RemoteException;
27import android.util.Log;
28import android.util.SparseArray;
29import android.view.Display;
30import android.view.IWindowManager;
31import android.view.View;
32import android.view.WindowManagerGlobal;
33
Charles Chen64172bb2019-04-22 17:30:29 +080034import androidx.annotation.Nullable;
35
Charles Chen54fce2c2019-03-13 18:17:29 +080036import com.android.internal.annotations.VisibleForTesting;
Matthew Ng94380652019-04-08 13:43:07 -070037import com.android.internal.statusbar.RegisterStatusBarResult;
Charles Chen10ca70b2018-11-28 00:03:38 +080038import com.android.systemui.Dependency;
shawnlin87af5382019-09-13 14:13:13 +080039import com.android.systemui.assist.AssistHandleViewController;
Dave Mankofff4736812019-10-18 17:25:50 -040040import com.android.systemui.dagger.qualifiers.MainHandler;
Charles Chen10ca70b2018-11-28 00:03:38 +080041import com.android.systemui.plugins.DarkIconDispatcher;
Charles Chen3dedec32019-01-24 22:19:37 +080042import com.android.systemui.statusbar.CommandQueue.Callbacks;
Charles Chen8c9a83f2018-12-18 17:44:10 +080043import com.android.systemui.statusbar.phone.AutoHideController;
Charles Chen10ca70b2018-11-28 00:03:38 +080044import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
45import com.android.systemui.statusbar.phone.LightBarController;
46import com.android.systemui.statusbar.phone.NavigationBarFragment;
47import com.android.systemui.statusbar.phone.NavigationBarView;
48import com.android.systemui.statusbar.policy.BatteryController;
49
50import javax.inject.Inject;
Charles Chen10ca70b2018-11-28 00:03:38 +080051import javax.inject.Singleton;
52
53
54/** A controller to handle navigation bars. */
55@Singleton
Riddle Hsucf33f1c2019-02-18 21:20:51 +080056public class NavigationBarController implements Callbacks {
Charles Chen10ca70b2018-11-28 00:03:38 +080057
Winson Chungfacf2132019-04-15 17:39:49 -070058 private static final String TAG = NavigationBarController.class.getSimpleName();
Charles Chen10ca70b2018-11-28 00:03:38 +080059
60 private final Context mContext;
61 private final Handler mHandler;
62 private final DisplayManager mDisplayManager;
63
64 /** A displayId - nav bar maps. */
Charles Chen54fce2c2019-03-13 18:17:29 +080065 @VisibleForTesting
66 SparseArray<NavigationBarFragment> mNavigationBars = new SparseArray<>();
Charles Chen10ca70b2018-11-28 00:03:38 +080067
68 @Inject
Dave Mankofff4736812019-10-18 17:25:50 -040069 public NavigationBarController(Context context, @MainHandler Handler handler) {
Charles Chen10ca70b2018-11-28 00:03:38 +080070 mContext = context;
71 mHandler = handler;
72 mDisplayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
Winson Chunga3132982019-04-08 13:27:47 -070073 CommandQueue commandQueue = getComponent(mContext, CommandQueue.class);
74 if (commandQueue != null) {
75 commandQueue.addCallback(this);
76 }
Charles Chen10ca70b2018-11-28 00:03:38 +080077 }
78
79 @Override
Charles Chen10ca70b2018-11-28 00:03:38 +080080 public void onDisplayRemoved(int displayId) {
81 removeNavigationBar(displayId);
82 }
83
84 @Override
Charles Chen3dedec32019-01-24 22:19:37 +080085 public void onDisplayReady(int displayId) {
86 Display display = mDisplayManager.getDisplay(displayId);
Matthew Ng94380652019-04-08 13:43:07 -070087 createNavigationBar(display, null);
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 */
Matthew Ng94380652019-04-08 13:43:07 -070097 public void createNavigationBars(final boolean includeDefaultDisplay,
98 RegisterStatusBarResult result) {
Charles Chen10ca70b2018-11-28 00:03:38 +080099 Display[] displays = mDisplayManager.getDisplays();
100 for (Display display : displays) {
101 if (includeDefaultDisplay || display.getDisplayId() != DEFAULT_DISPLAY) {
Matthew Ng94380652019-04-08 13:43:07 -0700102 createNavigationBar(display, result);
Charles Chen10ca70b2018-11-28 00:03:38 +0800103 }
104 }
105 }
106
107 /**
108 * Adds a navigation bar on default display or an external display if the display supports
109 * system decorations.
110 *
111 * @param display the display to add navigation bar on.
112 */
Charles Chen54fce2c2019-03-13 18:17:29 +0800113 @VisibleForTesting
Matthew Ng94380652019-04-08 13:43:07 -0700114 void createNavigationBar(Display display, RegisterStatusBarResult result) {
Andrii Kuliandd989612019-02-21 12:13:28 -0800115 if (display == null) {
Charles Chen10ca70b2018-11-28 00:03:38 +0800116 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)
Lucas Dupind236ee32019-10-08 15:33:59 -0700154 : new AutoHideController(context, mHandler,
155 Dependency.get(NotificationRemoteInputManager.class),
156 Dependency.get(IWindowManager.class));
Charles Chen8c9a83f2018-12-18 17:44:10 +0800157 navBar.setAutoHideController(autoHideController);
Jorim Jaggi956ca412019-01-07 14:49:14 +0100158 navBar.restoreAppearanceAndTransientState();
Charles Chen10ca70b2018-11-28 00:03:38 +0800159 mNavigationBars.append(displayId, navBar);
Matthew Ng94380652019-04-08 13:43:07 -0700160
161 if (result != null) {
162 navBar.setImeWindowStatus(display.getDisplayId(), result.mImeToken,
163 result.mImeWindowVis, result.mImeBackDisposition,
164 result.mShowImeSwitcher);
165 }
Charles Chen10ca70b2018-11-28 00:03:38 +0800166 });
167 }
168
Charles Chen10ca70b2018-11-28 00:03:38 +0800169 private void removeNavigationBar(int displayId) {
170 NavigationBarFragment navBar = mNavigationBars.get(displayId);
171 if (navBar != null) {
172 View navigationWindow = navBar.getView().getRootView();
173 WindowManagerGlobal.getInstance()
174 .removeView(navigationWindow, true /* immediate */);
175 mNavigationBars.remove(displayId);
176 }
177 }
178
179 /** @see NavigationBarFragment#checkNavBarModes() */
180 public void checkNavBarModes(int displayId) {
181 NavigationBarFragment navBar = mNavigationBars.get(displayId);
182 if (navBar != null) {
183 navBar.checkNavBarModes();
184 }
185 }
186
187 /** @see NavigationBarFragment#finishBarAnimations() */
188 public void finishBarAnimations(int displayId) {
189 NavigationBarFragment navBar = mNavigationBars.get(displayId);
190 if (navBar != null) {
191 navBar.finishBarAnimations();
192 }
193 }
194
195 /** @see NavigationBarFragment#touchAutoDim() */
196 public void touchAutoDim(int displayId) {
197 NavigationBarFragment navBar = mNavigationBars.get(displayId);
198 if (navBar != null) {
199 navBar.touchAutoDim();
200 }
201 }
202
203 /** @see NavigationBarFragment#transitionTo(int, boolean) */
204 public void transitionTo(int displayId, @TransitionMode int barMode, boolean animate) {
205 NavigationBarFragment navBar = mNavigationBars.get(displayId);
206 if (navBar != null) {
207 navBar.transitionTo(barMode, animate);
208 }
209 }
210
Charles Chen10ca70b2018-11-28 00:03:38 +0800211 /** @see NavigationBarFragment#disableAnimationsDuringHide(long) */
212 public void disableAnimationsDuringHide(int displayId, long delay) {
213 NavigationBarFragment navBar = mNavigationBars.get(displayId);
214 if (navBar != null) {
215 navBar.disableAnimationsDuringHide(delay);
216 }
217 }
218
219 /** @return {@link NavigationBarView} on the default display. */
Charles Chen64172bb2019-04-22 17:30:29 +0800220 public @Nullable NavigationBarView getDefaultNavigationBarView() {
221 return getNavigationBarView(DEFAULT_DISPLAY);
222 }
223
224 /**
225 * @param displayId the ID of display which Navigation bar is on
226 * @return {@link NavigationBarView} on the display with {@code displayId}.
227 * {@code null} if no navigation bar on that display.
228 */
229 public @Nullable NavigationBarView getNavigationBarView(int displayId) {
230 NavigationBarFragment navBar = mNavigationBars.get(displayId);
Charles Chen10ca70b2018-11-28 00:03:38 +0800231 return (navBar == null) ? null : (NavigationBarView) navBar.getView();
232 }
Winson Chunga3132982019-04-08 13:27:47 -0700233
234 /** @return {@link NavigationBarFragment} on the default display. */
Govinda Wasserman57236572019-10-14 13:48:43 -0400235 @Nullable
Winson Chunga3132982019-04-08 13:27:47 -0700236 public NavigationBarFragment getDefaultNavigationBarFragment() {
237 return mNavigationBars.get(DEFAULT_DISPLAY);
238 }
shawnlin87af5382019-09-13 14:13:13 +0800239
240 /** @return {@link AssistHandleViewController} (only on the default display). */
Govinda Wasserman57236572019-10-14 13:48:43 -0400241 @Nullable
shawnlin87af5382019-09-13 14:13:13 +0800242 public AssistHandleViewController getAssistHandlerViewController() {
Lucas Dupin131c76d2019-10-01 12:59:39 -0700243 NavigationBarFragment navBar = getDefaultNavigationBarFragment();
244 return navBar == null ? null : navBar.getAssistHandlerViewController();
shawnlin87af5382019-09-13 14:13:13 +0800245 }
Charles Chen10ca70b2018-11-28 00:03:38 +0800246}