blob: af92767efc49fc012ac785907f8bc4afe402210b [file] [log] [blame]
Heemin Seog1a39dea2019-10-16 15:58:21 -07001/*
2 * Copyright (C) 2019 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.navigationbar.car;
18
Heemin Seog1a39dea2019-10-16 15:58:21 -070019import android.content.Context;
20import android.graphics.PixelFormat;
21import android.inputmethodservice.InputMethodService;
22import android.os.Handler;
23import android.os.IBinder;
24import android.os.RemoteException;
25import android.os.ServiceManager;
26import android.view.Display;
27import android.view.Gravity;
Heemin Seog8d6ec6a72019-10-25 14:34:11 -070028import android.view.View;
Heemin Seog1a39dea2019-10-16 15:58:21 -070029import android.view.ViewGroup;
30import android.view.WindowManager;
31
32import com.android.internal.statusbar.IStatusBarService;
33import com.android.internal.statusbar.RegisterStatusBarResult;
34import com.android.systemui.R;
35import com.android.systemui.SystemUI;
Dave Mankofff4736812019-10-18 17:25:50 -040036import com.android.systemui.dagger.qualifiers.MainHandler;
Heemin Seog1a39dea2019-10-16 15:58:21 -070037import com.android.systemui.shared.system.ActivityManagerWrapper;
38import com.android.systemui.statusbar.CommandQueue;
39import com.android.systemui.statusbar.NavigationBarController;
Heemin Seog1a39dea2019-10-16 15:58:21 -070040import com.android.systemui.statusbar.policy.DeviceProvisionedController;
41import com.android.systemui.statusbar.policy.KeyguardStateController;
42
43import java.io.FileDescriptor;
44import java.io.PrintWriter;
45
46import javax.inject.Inject;
Heemin Seog1a39dea2019-10-16 15:58:21 -070047
48import dagger.Lazy;
49
50/** Navigation bars customized for the automotive use case. */
51public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks {
52
Heemin Seogfcccab72019-10-22 08:30:23 -070053 private final CarNavigationBarController mCarNavigationBarController;
Heemin Seog1a39dea2019-10-16 15:58:21 -070054 private final WindowManager mWindowManager;
55 private final DeviceProvisionedController mDeviceProvisionedController;
Heemin Seog4a689482019-11-04 10:37:43 -080056 private final CommandQueue mCommandQueue;
Heemin Seog1a39dea2019-10-16 15:58:21 -070057 private final Lazy<FacetButtonTaskStackListener> mFacetButtonTaskStackListener;
58 private final Handler mMainHandler;
59 private final Lazy<KeyguardStateController> mKeyguardStateController;
Heemin Seog1a39dea2019-10-16 15:58:21 -070060 private final Lazy<NavigationBarController> mNavigationBarController;
Heemin Seog1a39dea2019-10-16 15:58:21 -070061
62 private IStatusBarService mBarService;
Heemin Seog1a39dea2019-10-16 15:58:21 -070063 private ActivityManagerWrapper mActivityManagerWrapper;
64
65 // If the nav bar should be hidden when the soft keyboard is visible.
66 private boolean mHideNavBarForKeyboard;
67 private boolean mBottomNavBarVisible;
68
69 // Nav bar views.
70 private ViewGroup mNavigationBarWindow;
71 private ViewGroup mLeftNavigationBarWindow;
72 private ViewGroup mRightNavigationBarWindow;
73 private CarNavigationBarView mNavigationBarView;
74 private CarNavigationBarView mLeftNavigationBarView;
75 private CarNavigationBarView mRightNavigationBarView;
76
77 // To be attached to the navigation bars such that they can close the notification panel if
78 // it's open.
79 private boolean mDeviceIsSetUpForUser = true;
80
Heemin Seog1a39dea2019-10-16 15:58:21 -070081 @Inject
82 public CarNavigationBar(Context context,
Heemin Seogfcccab72019-10-22 08:30:23 -070083 CarNavigationBarController carNavigationBarController,
Heemin Seog1a39dea2019-10-16 15:58:21 -070084 WindowManager windowManager,
85 DeviceProvisionedController deviceProvisionedController,
Heemin Seog4a689482019-11-04 10:37:43 -080086 CommandQueue commandQueue,
Heemin Seog1a39dea2019-10-16 15:58:21 -070087 Lazy<FacetButtonTaskStackListener> facetButtonTaskStackListener,
Dave Mankofff4736812019-10-18 17:25:50 -040088 @MainHandler Handler mainHandler,
Heemin Seog1a39dea2019-10-16 15:58:21 -070089 Lazy<KeyguardStateController> keyguardStateController,
Heemin Seogfcccab72019-10-22 08:30:23 -070090 Lazy<NavigationBarController> navigationBarController) {
Heemin Seog1a39dea2019-10-16 15:58:21 -070091 super(context);
Heemin Seogfcccab72019-10-22 08:30:23 -070092 mCarNavigationBarController = carNavigationBarController;
Heemin Seog1a39dea2019-10-16 15:58:21 -070093 mWindowManager = windowManager;
94 mDeviceProvisionedController = deviceProvisionedController;
Heemin Seog4a689482019-11-04 10:37:43 -080095 mCommandQueue = commandQueue;
Heemin Seog1a39dea2019-10-16 15:58:21 -070096 mFacetButtonTaskStackListener = facetButtonTaskStackListener;
97 mMainHandler = mainHandler;
98 mKeyguardStateController = keyguardStateController;
Heemin Seog1a39dea2019-10-16 15:58:21 -070099 mNavigationBarController = navigationBarController;
Heemin Seog1a39dea2019-10-16 15:58:21 -0700100 }
101
102 @Override
103 public void start() {
104 // Set initial state.
105 mHideNavBarForKeyboard = mContext.getResources().getBoolean(
106 com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard);
107 mBottomNavBarVisible = false;
108
Heemin Seog1a39dea2019-10-16 15:58:21 -0700109 // Get bar service.
110 mBarService = IStatusBarService.Stub.asInterface(
111 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
112
113 // Connect into the status bar manager service
Heemin Seog1a39dea2019-10-16 15:58:21 -0700114 mCommandQueue.addCallback(this);
115
116 RegisterStatusBarResult result = null;
117 try {
118 result = mBarService.registerStatusBar(mCommandQueue);
119 } catch (RemoteException ex) {
120 ex.rethrowFromSystemServer();
121 }
122
123 mDeviceIsSetUpForUser = mDeviceProvisionedController.isCurrentUserSetup();
124 mDeviceProvisionedController.addCallback(
125 new DeviceProvisionedController.DeviceProvisionedListener() {
126 @Override
127 public void onUserSetupChanged() {
128 mMainHandler.post(() -> restartNavBarsIfNecessary());
129 }
130
131 @Override
132 public void onUserSwitched() {
133 mMainHandler.post(() -> restartNavBarsIfNecessary());
134 }
135 });
136
137 createNavigationBar(result);
138
139 mActivityManagerWrapper = ActivityManagerWrapper.getInstance();
140 mActivityManagerWrapper.registerTaskStackListener(mFacetButtonTaskStackListener.get());
141
Heemin Seogfcccab72019-10-22 08:30:23 -0700142 mCarNavigationBarController.connectToHvac();
Heemin Seog1a39dea2019-10-16 15:58:21 -0700143 }
144
145 private void restartNavBarsIfNecessary() {
146 boolean currentUserSetup = mDeviceProvisionedController.isCurrentUserSetup();
147 if (mDeviceIsSetUpForUser != currentUserSetup) {
148 mDeviceIsSetUpForUser = currentUserSetup;
149 restartNavBars();
150 }
151 }
152
153 /**
154 * Remove all content from navbars and rebuild them. Used to allow for different nav bars
155 * before and after the device is provisioned. . Also for change of density and font size.
156 */
157 private void restartNavBars() {
158 // remove and reattach all hvac components such that we don't keep a reference to unused
159 // ui elements
Heemin Seogfcccab72019-10-22 08:30:23 -0700160 mCarNavigationBarController.removeAllFromHvac();
Heemin Seog1a39dea2019-10-16 15:58:21 -0700161
162 if (mNavigationBarWindow != null) {
163 mNavigationBarWindow.removeAllViews();
164 mNavigationBarView = null;
165 }
166
167 if (mLeftNavigationBarWindow != null) {
168 mLeftNavigationBarWindow.removeAllViews();
169 mLeftNavigationBarView = null;
170 }
171
172 if (mRightNavigationBarWindow != null) {
173 mRightNavigationBarWindow.removeAllViews();
174 mRightNavigationBarView = null;
175 }
176
177 buildNavBarContent();
178 // If the UI was rebuilt (day/night change) while the keyguard was up we need to
179 // correctly respect that state.
180 if (mKeyguardStateController.get().isShowing()) {
181 updateNavBarForKeyguardContent();
182 }
Heemin Seog1a39dea2019-10-16 15:58:21 -0700183 }
184
185 private void createNavigationBar(RegisterStatusBarResult result) {
186 buildNavBarWindows();
187 buildNavBarContent();
188 attachNavBarWindows();
189
190 // Try setting up the initial state of the nav bar if applicable.
191 if (result != null) {
192 setImeWindowStatus(Display.DEFAULT_DISPLAY, result.mImeToken,
193 result.mImeWindowVis, result.mImeBackDisposition,
194 result.mShowImeSwitcher);
195 }
196
197 // There has been a car customized nav bar on the default display, so just create nav bars
198 // on external displays.
199 mNavigationBarController.get().createNavigationBars(/* includeDefaultDisplay= */ false,
200 result);
201 }
202
203 private void buildNavBarWindows() {
Heemin Seogfcccab72019-10-22 08:30:23 -0700204 mNavigationBarWindow = mCarNavigationBarController.getBottomWindow();
205 mLeftNavigationBarWindow = mCarNavigationBarController.getLeftWindow();
206 mRightNavigationBarWindow = mCarNavigationBarController.getRightWindow();
Heemin Seog1a39dea2019-10-16 15:58:21 -0700207 }
208
209 private void buildNavBarContent() {
Heemin Seogfcccab72019-10-22 08:30:23 -0700210 mNavigationBarView = mCarNavigationBarController.getBottomBar(mDeviceIsSetUpForUser);
211 if (mNavigationBarView != null) {
Heemin Seog1a39dea2019-10-16 15:58:21 -0700212 mNavigationBarWindow.addView(mNavigationBarView);
Heemin Seog1a39dea2019-10-16 15:58:21 -0700213 }
214
Heemin Seogfcccab72019-10-22 08:30:23 -0700215 mLeftNavigationBarView = mCarNavigationBarController.getLeftBar(mDeviceIsSetUpForUser);
216 if (mLeftNavigationBarView != null) {
Heemin Seog1a39dea2019-10-16 15:58:21 -0700217 mLeftNavigationBarWindow.addView(mLeftNavigationBarView);
Heemin Seog1a39dea2019-10-16 15:58:21 -0700218 }
219
Heemin Seogfcccab72019-10-22 08:30:23 -0700220 mRightNavigationBarView = mCarNavigationBarController.getRightBar(mDeviceIsSetUpForUser);
221 if (mRightNavigationBarView != null) {
Heemin Seog1a39dea2019-10-16 15:58:21 -0700222 mRightNavigationBarWindow.addView(mRightNavigationBarView);
Heemin Seog1a39dea2019-10-16 15:58:21 -0700223 }
224 }
225
226 private void attachNavBarWindows() {
Heemin Seogfcccab72019-10-22 08:30:23 -0700227 if (mNavigationBarWindow != null && !mBottomNavBarVisible) {
Heemin Seog1a39dea2019-10-16 15:58:21 -0700228 mBottomNavBarVisible = true;
229
230 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
231 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
232 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
233 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
234 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
235 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
236 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
237 PixelFormat.TRANSLUCENT);
238 lp.setTitle("CarNavigationBar");
239 lp.windowAnimations = 0;
240 mWindowManager.addView(mNavigationBarWindow, lp);
241 }
242
Heemin Seogfcccab72019-10-22 08:30:23 -0700243 if (mLeftNavigationBarWindow != null) {
Heemin Seog1a39dea2019-10-16 15:58:21 -0700244 int width = mContext.getResources().getDimensionPixelSize(
245 R.dimen.car_left_navigation_bar_width);
246 WindowManager.LayoutParams leftlp = new WindowManager.LayoutParams(
247 width, ViewGroup.LayoutParams.MATCH_PARENT,
248 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
249 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
250 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
251 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
252 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
253 PixelFormat.TRANSLUCENT);
254 leftlp.setTitle("LeftCarNavigationBar");
255 leftlp.windowAnimations = 0;
256 leftlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
257 leftlp.gravity = Gravity.LEFT;
258 mWindowManager.addView(mLeftNavigationBarWindow, leftlp);
259 }
Heemin Seogfcccab72019-10-22 08:30:23 -0700260 if (mRightNavigationBarWindow != null) {
Heemin Seog1a39dea2019-10-16 15:58:21 -0700261 int width = mContext.getResources().getDimensionPixelSize(
262 R.dimen.car_right_navigation_bar_width);
263 WindowManager.LayoutParams rightlp = new WindowManager.LayoutParams(
264 width, ViewGroup.LayoutParams.MATCH_PARENT,
265 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
266 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
267 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
268 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
269 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
270 PixelFormat.TRANSLUCENT);
271 rightlp.setTitle("RightCarNavigationBar");
272 rightlp.windowAnimations = 0;
273 rightlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
274 rightlp.gravity = Gravity.RIGHT;
275 mWindowManager.addView(mRightNavigationBarWindow, rightlp);
276 }
277 }
278
279 /**
280 * We register for soft keyboard visibility events such that we can hide the navigation bar
281 * giving more screen space to the IME. Note: this is optional and controlled by
282 * {@code com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard}.
283 */
284 @Override
285 public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
286 boolean showImeSwitcher) {
287 if (!mHideNavBarForKeyboard) {
288 return;
289 }
290
291 if (mContext.getDisplay().getDisplayId() != displayId) {
292 return;
293 }
294
295 boolean isKeyboardVisible = (vis & InputMethodService.IME_VISIBLE) != 0;
Heemin Seog8d6ec6a72019-10-25 14:34:11 -0700296 mCarNavigationBarController.setBottomWindowVisibility(
297 isKeyboardVisible ? View.GONE : View.VISIBLE);
Heemin Seog1a39dea2019-10-16 15:58:21 -0700298 }
299
300 private void updateNavBarForKeyguardContent() {
301 if (mNavigationBarView != null) {
302 mNavigationBarView.showKeyguardButtons();
303 }
304 if (mLeftNavigationBarView != null) {
305 mLeftNavigationBarView.showKeyguardButtons();
306 }
307 if (mRightNavigationBarView != null) {
308 mRightNavigationBarView.showKeyguardButtons();
309 }
310 }
311
312 @Override
313 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
314 pw.print(" mTaskStackListener=");
315 pw.println(mFacetButtonTaskStackListener.get());
316 pw.print(" mNavigationBarView=");
317 pw.println(mNavigationBarView);
318 }
319}