blob: 14dc272d1c5e88ee2d4541d2e5dffa6c1b411ea9 [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;
Charles Chen10ca70b2018-11-28 00:03:38 +080026import 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 Chen3dedec32019-01-24 22:19:37 +080037import com.android.systemui.statusbar.CommandQueue.Callbacks;
Charles Chen8c9a83f2018-12-18 17:44:10 +080038import com.android.systemui.statusbar.phone.AutoHideController;
Charles Chen10ca70b2018-11-28 00:03:38 +080039import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
40import com.android.systemui.statusbar.phone.LightBarController;
41import com.android.systemui.statusbar.phone.NavigationBarFragment;
42import com.android.systemui.statusbar.phone.NavigationBarView;
43import com.android.systemui.statusbar.policy.BatteryController;
44
45import javax.inject.Inject;
46import javax.inject.Named;
47import javax.inject.Singleton;
48
49
50/** A controller to handle navigation bars. */
51@Singleton
Riddle Hsucf33f1c2019-02-18 21:20:51 +080052public class NavigationBarController implements Callbacks {
Charles Chen10ca70b2018-11-28 00:03:38 +080053
54 private static final String TAG = NavigationBarController.class.getName();
55
56 private final Context mContext;
57 private final Handler mHandler;
58 private final DisplayManager mDisplayManager;
59
60 /** A displayId - nav bar maps. */
61 private SparseArray<NavigationBarFragment> mNavigationBars = new SparseArray<>();
62
63 @Inject
64 public NavigationBarController(Context context, @Named(MAIN_HANDLER_NAME) Handler handler) {
65 mContext = context;
66 mHandler = handler;
67 mDisplayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
Charles Chen3dedec32019-01-24 22:19:37 +080068 getComponent(mContext, CommandQueue.class).addCallback(this);
Charles Chen10ca70b2018-11-28 00:03:38 +080069 }
70
71 @Override
Charles Chen10ca70b2018-11-28 00:03:38 +080072 public void onDisplayRemoved(int displayId) {
73 removeNavigationBar(displayId);
74 }
75
76 @Override
Charles Chen3dedec32019-01-24 22:19:37 +080077 public void onDisplayReady(int displayId) {
78 Display display = mDisplayManager.getDisplay(displayId);
79 createNavigationBar(display);
Charles Chen10ca70b2018-11-28 00:03:38 +080080 }
81
82 // TODO(b/117478341): I use {@code includeDefaultDisplay} to make this method compatible to
83 // CarStatusBar because they have their own nav bar. Think about a better way for it.
84 /**
85 * Creates navigation bars when car/status bar initializes.
86 *
87 * @param includeDefaultDisplay {@code true} to create navigation bar on default display.
88 */
89 public void createNavigationBars(final boolean includeDefaultDisplay) {
90 Display[] displays = mDisplayManager.getDisplays();
91 for (Display display : displays) {
92 if (includeDefaultDisplay || display.getDisplayId() != DEFAULT_DISPLAY) {
93 createNavigationBar(display);
94 }
95 }
96 }
97
98 /**
99 * Adds a navigation bar on default display or an external display if the display supports
100 * system decorations.
101 *
102 * @param display the display to add navigation bar on.
103 */
104 private void createNavigationBar(Display display) {
Andrii Kuliandd989612019-02-21 12:13:28 -0800105 if (display == null) {
Charles Chen10ca70b2018-11-28 00:03:38 +0800106 return;
107 }
108
109 final int displayId = display.getDisplayId();
110 final boolean isOnDefaultDisplay = displayId == DEFAULT_DISPLAY;
111 final IWindowManager wms = WindowManagerGlobal.getWindowManagerService();
112
113 try {
114 if (!wms.hasNavigationBar(displayId)) {
115 return;
116 }
117 } catch (RemoteException e) {
118 // Cannot get wms, just return with warning message.
119 Log.w(TAG, "Cannot get WindowManager.");
120 return;
121 }
122 final Context context = isOnDefaultDisplay
123 ? mContext
124 : mContext.createDisplayContext(display);
125 NavigationBarFragment.create(context, (tag, fragment) -> {
126 NavigationBarFragment navBar = (NavigationBarFragment) fragment;
127
128 // Unfortunately, we still need it because status bar needs LightBarController
129 // before notifications creation. We cannot directly use getLightBarController()
130 // from NavigationBarFragment directly.
Charles Chen8c9a83f2018-12-18 17:44:10 +0800131 LightBarController lightBarController = isOnDefaultDisplay
Charles Chen10ca70b2018-11-28 00:03:38 +0800132 ? Dependency.get(LightBarController.class)
133 : new LightBarController(context,
134 Dependency.get(DarkIconDispatcher.class),
135 Dependency.get(BatteryController.class));
Charles Chen8c9a83f2018-12-18 17:44:10 +0800136 navBar.setLightBarController(lightBarController);
137
138 // TODO(b/118592525): to support multi-display, we start to add something which is
139 // per-display, while others may be global. I think it's time to add
140 // a new class maybe named DisplayDependency to solve per-display
141 // Dependency problem.
142 AutoHideController autoHideController = isOnDefaultDisplay
143 ? Dependency.get(AutoHideController.class)
144 : new AutoHideController(context, mHandler);
145 navBar.setAutoHideController(autoHideController);
Charles Chen10ca70b2018-11-28 00:03:38 +0800146 navBar.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
147 mNavigationBars.append(displayId, navBar);
148 });
149 }
150
Charles Chen10ca70b2018-11-28 00:03:38 +0800151 private void removeNavigationBar(int displayId) {
152 NavigationBarFragment navBar = mNavigationBars.get(displayId);
153 if (navBar != null) {
154 View navigationWindow = navBar.getView().getRootView();
155 WindowManagerGlobal.getInstance()
156 .removeView(navigationWindow, true /* immediate */);
157 mNavigationBars.remove(displayId);
158 }
159 }
160
161 /** @see NavigationBarFragment#checkNavBarModes() */
162 public void checkNavBarModes(int displayId) {
163 NavigationBarFragment navBar = mNavigationBars.get(displayId);
164 if (navBar != null) {
165 navBar.checkNavBarModes();
166 }
167 }
168
169 /** @see NavigationBarFragment#finishBarAnimations() */
170 public void finishBarAnimations(int displayId) {
171 NavigationBarFragment navBar = mNavigationBars.get(displayId);
172 if (navBar != null) {
173 navBar.finishBarAnimations();
174 }
175 }
176
177 /** @see NavigationBarFragment#touchAutoDim() */
178 public void touchAutoDim(int displayId) {
179 NavigationBarFragment navBar = mNavigationBars.get(displayId);
180 if (navBar != null) {
181 navBar.touchAutoDim();
182 }
183 }
184
185 /** @see NavigationBarFragment#transitionTo(int, boolean) */
186 public void transitionTo(int displayId, @TransitionMode int barMode, boolean animate) {
187 NavigationBarFragment navBar = mNavigationBars.get(displayId);
188 if (navBar != null) {
189 navBar.transitionTo(barMode, animate);
190 }
191 }
192
Charles Chen10ca70b2018-11-28 00:03:38 +0800193 /** @see NavigationBarFragment#disableAnimationsDuringHide(long) */
194 public void disableAnimationsDuringHide(int displayId, long delay) {
195 NavigationBarFragment navBar = mNavigationBars.get(displayId);
196 if (navBar != null) {
197 navBar.disableAnimationsDuringHide(delay);
198 }
199 }
200
201 /** @return {@link NavigationBarView} on the default display. */
202 public NavigationBarView getDefaultNavigationBarView() {
203 NavigationBarFragment navBar = mNavigationBars.get(DEFAULT_DISPLAY);
204 return (navBar == null) ? null : (NavigationBarView) navBar.getView();
205 }
206}