blob: d4cf272e8077803a0f4d6ad06aeb5d125d8fd8ff [file] [log] [blame]
Jason Monk49fa0162017-01-11 09:21:56 -05001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5 * except in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11 * KIND, either express or implied. See the License for the specific language governing
12 * permissions and limitations under the License.
13 */
14
15package com.android.systemui.statusbar.phone;
16
17import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
18import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
Charles Chen10ca70b2018-11-28 00:03:38 +080019import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
Jason Monk49fa0162017-01-11 09:21:56 -050020import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
Charles Chenf3d295c2018-11-30 18:15:21 +080021import static android.app.StatusBarManager.WindowType;
22import static android.app.StatusBarManager.WindowVisibleState;
Jason Monk49fa0162017-01-11 09:21:56 -050023import static android.app.StatusBarManager.windowStateToString;
Tiger Huang332793b2019-10-29 23:21:27 +080024import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
Jorim Jaggi956ca412019-01-07 14:49:14 +010025import static android.view.InsetsState.containsType;
26import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
Tiger Huang332793b2019-10-29 23:21:27 +080027import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
Winson Chung1aa24b92019-04-24 15:17:33 -070028import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
Jason Monk49fa0162017-01-11 09:21:56 -050029
Winson Chung2dbcf092018-10-24 13:00:41 -070030import static com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
Sunny Goyal247eb892019-04-24 11:36:37 -070031import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
32import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
Winson Chunga3132982019-04-08 13:27:47 -070033import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
Charles Chen10ca70b2018-11-28 00:03:38 +080034import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
Tracy Zhou1ac592c2018-07-25 13:47:37 -070035import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
Charles Chen10ca70b2018-11-28 00:03:38 +080036import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
Jason Monk49fa0162017-01-11 09:21:56 -050037import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
Tracy Zhou1ac592c2018-07-25 13:47:37 -070038import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
Charles Chen10ca70b2018-11-28 00:03:38 +080039import static com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
Jason Monk2a6ea9c2017-01-26 11:14:51 -050040import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_WINDOW_STATE;
41import static com.android.systemui.statusbar.phone.StatusBar.dumpBarTransitions;
Jason Monk49fa0162017-01-11 09:21:56 -050042
Casey Burkhardt048c2bc2016-12-08 16:09:20 -080043import android.accessibilityservice.AccessibilityServiceInfo;
Matthew Ng9c3bce52018-02-01 22:00:31 +000044import android.annotation.IdRes;
Jason Monk49fa0162017-01-11 09:21:56 -050045import android.annotation.Nullable;
Winson Chung67f5c8b2018-09-24 12:09:19 -070046import android.app.ActivityManager;
Wale Ogunwale65ebd952018-04-25 15:41:44 -070047import android.app.ActivityTaskManager;
Wale Ogunwale04d9cb52018-04-30 13:55:07 -070048import android.app.IActivityTaskManager;
Jason Monk49fa0162017-01-11 09:21:56 -050049import android.app.StatusBarManager;
50import android.content.BroadcastReceiver;
Casey Burkhardtb9dcd662017-03-20 15:10:16 -070051import android.content.ContentResolver;
Jason Monk49fa0162017-01-11 09:21:56 -050052import android.content.Context;
53import android.content.Intent;
54import android.content.IntentFilter;
55import android.content.res.Configuration;
Casey Burkhardt74922c62017-02-13 12:43:16 -080056import android.database.ContentObserver;
Jason Monk49fa0162017-01-11 09:21:56 -050057import android.graphics.PixelFormat;
Jason Monk49fa0162017-01-11 09:21:56 -050058import android.inputmethodservice.InputMethodService;
Matthew Ngadd4c392019-03-01 16:02:31 -080059import android.net.Uri;
Jason Monk49fa0162017-01-11 09:21:56 -050060import android.os.Binder;
61import android.os.Bundle;
62import android.os.Handler;
63import android.os.IBinder;
Matthew Ngadd4c392019-03-01 16:02:31 -080064import android.os.Looper;
Jason Monk49fa0162017-01-11 09:21:56 -050065import android.os.RemoteException;
66import android.os.UserHandle;
Casey Burkhardt74922c62017-02-13 12:43:16 -080067import android.provider.Settings;
Jason Monk49fa0162017-01-11 09:21:56 -050068import android.telecom.TelecomManager;
69import android.text.TextUtils;
70import android.util.Log;
Andrii Kulian3ddd7de2018-10-10 00:33:19 -070071import android.view.Display;
Tiger Huang332793b2019-10-29 23:21:27 +080072import android.view.InsetsState.InternalInsetsType;
Jason Monk49fa0162017-01-11 09:21:56 -050073import android.view.KeyEvent;
74import android.view.LayoutInflater;
75import android.view.MotionEvent;
Mike Digman85ff7fa2018-01-23 14:59:52 -080076import android.view.Surface;
Jason Monk49fa0162017-01-11 09:21:56 -050077import android.view.View;
78import android.view.ViewGroup;
Jorim Jaggi956ca412019-01-07 14:49:14 +010079import android.view.WindowInsetsController.Appearance;
Jason Monk49fa0162017-01-11 09:21:56 -050080import android.view.WindowManager;
81import android.view.WindowManager.LayoutParams;
Jason Monk49fa0162017-01-11 09:21:56 -050082import android.view.accessibility.AccessibilityEvent;
83import android.view.accessibility.AccessibilityManager;
Jason Monk91e587e2017-04-13 13:41:23 -040084import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
Jason Monk49fa0162017-01-11 09:21:56 -050085
Matthew Ng761562d2018-09-17 11:13:21 -070086import androidx.annotation.VisibleForTesting;
87
Jason Monk49fa0162017-01-11 09:21:56 -050088import com.android.internal.logging.MetricsLogger;
89import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Jason Monkea03be12017-12-04 11:08:41 -050090import com.android.internal.util.LatencyTracker;
Jorim Jaggi956ca412019-01-07 14:49:14 +010091import com.android.internal.view.AppearanceRegion;
Jason Monk49fa0162017-01-11 09:21:56 -050092import com.android.systemui.R;
shawnlin87af5382019-09-13 14:13:13 +080093import com.android.systemui.assist.AssistHandleViewController;
Jason Monk49fa0162017-01-11 09:21:56 -050094import com.android.systemui.assist.AssistManager;
Fabian Kozynskiff5e91f2019-09-24 15:38:08 -040095import com.android.systemui.broadcast.BroadcastDispatcher;
Dave Mankoff00e8a2f2019-12-18 16:59:49 -050096import com.android.systemui.dagger.qualifiers.Main;
Jason Monk49fa0162017-01-11 09:21:56 -050097import com.android.systemui.fragments.FragmentHostManager;
98import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
Vinit Nayak59b114e62019-08-12 11:50:00 -070099import com.android.systemui.model.SysUiState;
Beverly8fdb5332019-02-04 14:29:49 -0500100import com.android.systemui.plugins.statusbar.StatusBarStateController;
Andrii Kulian3ddd7de2018-10-10 00:33:19 -0700101import com.android.systemui.recents.OverviewProxyService;
Jason Monk49fa0162017-01-11 09:21:56 -0500102import com.android.systemui.recents.Recents;
Mike Digman7d092772018-01-11 12:10:32 -0800103import com.android.systemui.shared.system.ActivityManagerWrapper;
Sunny Goyala6a58122019-04-02 10:20:29 -0700104import com.android.systemui.shared.system.QuickStepContract;
Jason Monk49fa0162017-01-11 09:21:56 -0500105import com.android.systemui.stackdivider.Divider;
106import com.android.systemui.statusbar.CommandQueue;
107import com.android.systemui.statusbar.CommandQueue.Callbacks;
Charles Chen10ca70b2018-11-28 00:03:38 +0800108import com.android.systemui.statusbar.StatusBarState;
Matthew Ng761562d2018-09-17 11:13:21 -0700109import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
110import com.android.systemui.statusbar.phone.ContextualButton.ContextButtonListener;
Jason Monk91e587e2017-04-13 13:41:23 -0400111import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
Jason Monk297c04e2018-08-23 17:16:59 -0400112import com.android.systemui.statusbar.policy.DeviceProvisionedController;
Jason Monk49fa0162017-01-11 09:21:56 -0500113import com.android.systemui.statusbar.policy.KeyButtonView;
Jason Monk8e4e4cb2018-12-04 11:10:24 -0500114import com.android.systemui.util.LifecycleFragment;
Jason Monk49fa0162017-01-11 09:21:56 -0500115
116import java.io.FileDescriptor;
117import java.io.PrintWriter;
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800118import java.util.List;
Jason Monk49fa0162017-01-11 09:21:56 -0500119import java.util.Locale;
Dave Mankoffae3b4322019-11-05 19:48:24 -0500120import java.util.Optional;
Matthew Ng761562d2018-09-17 11:13:21 -0700121import java.util.function.Consumer;
Jason Monk49fa0162017-01-11 09:21:56 -0500122
Jason Monk9424af72018-12-19 14:17:26 -0500123import javax.inject.Inject;
124
Dave Mankoff4dd47fa2019-11-07 10:44:48 -0500125import dagger.Lazy;
126
Jason Monk49fa0162017-01-11 09:21:56 -0500127/**
128 * Fragment containing the NavigationBarFragment. Contains logic for what happens
129 * on clicks and view states of the nav bar.
130 */
Winson Chung1aa24b92019-04-24 15:17:33 -0700131public class NavigationBarFragment extends LifecycleFragment implements Callbacks,
132 NavigationModeController.ModeChangedListener {
Jason Monk49fa0162017-01-11 09:21:56 -0500133
Jason Monkd4afe152017-05-01 15:37:43 -0400134 public static final String TAG = "NavigationBar";
Jason Monk49fa0162017-01-11 09:21:56 -0500135 private static final boolean DEBUG = false;
136 private static final String EXTRA_DISABLE_STATE = "disabled_state";
Mike Digmandd2f49e2018-03-16 10:54:22 -0700137 private static final String EXTRA_DISABLE2_STATE = "disabled2_state";
Jorim Jaggi956ca412019-01-07 14:49:14 +0100138 private static final String EXTRA_APPEARANCE = "appearance";
139 private static final String EXTRA_TRANSIENT_STATE = "transient_state";
Jason Monk49fa0162017-01-11 09:21:56 -0500140
141 /** Allow some time inbetween the long press for back and recents. */
142 private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
Charles Chen8c9a83f2018-12-18 17:44:10 +0800143 private static final long AUTODIM_TIMEOUT_MS = 2250;
Jason Monk49fa0162017-01-11 09:21:56 -0500144
Jason Monk9424af72018-12-19 14:17:26 -0500145 private final AccessibilityManagerWrapper mAccessibilityManagerWrapper;
146 protected final AssistManager mAssistManager;
Vinit Nayak59b114e62019-08-12 11:50:00 -0700147 private SysUiState mSysUiFlagsContainer;
Jason Monk9424af72018-12-19 14:17:26 -0500148 private final MetricsLogger mMetricsLogger;
149 private final DeviceProvisionedController mDeviceProvisionedController;
Winson Chung9e572492019-06-07 10:48:45 -0700150 private final StatusBarStateController mStatusBarStateController;
Winson Chung52d938d2019-09-25 16:50:05 -0700151 private final NavigationModeController mNavigationModeController;
Jason Monk297c04e2018-08-23 17:16:59 -0400152
Jason Monk49fa0162017-01-11 09:21:56 -0500153 protected NavigationBarView mNavigationBarView = null;
Jason Monk49fa0162017-01-11 09:21:56 -0500154
Charles Chenf3d295c2018-11-30 18:15:21 +0800155 private @WindowVisibleState int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
Jason Monk49fa0162017-01-11 09:21:56 -0500156
157 private int mNavigationIconHints = 0;
Charles Chen10ca70b2018-11-28 00:03:38 +0800158 private @TransitionMode int mNavigationBarMode;
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800159 private AccessibilityManager mAccessibilityManager;
Casey Burkhardt74922c62017-02-13 12:43:16 -0800160 private MagnificationContentObserver mMagnificationObserver;
Casey Burkhardtb9dcd662017-03-20 15:10:16 -0700161 private ContentResolver mContentResolver;
Matthew Ngadd4c392019-03-01 16:02:31 -0800162 private boolean mAssistantAvailable;
Jason Monk49fa0162017-01-11 09:21:56 -0500163
164 private int mDisabledFlags1;
Mike Digmandd2f49e2018-03-16 10:54:22 -0700165 private int mDisabledFlags2;
Dave Mankoff4dd47fa2019-11-07 10:44:48 -0500166 private final Lazy<StatusBar> mStatusBarLazy;
Heemin Seogba6337f2019-12-10 15:34:37 -0800167 private final ShadeController mShadeController;
Dave Mankoff4dd47fa2019-11-07 10:44:48 -0500168 private Recents mRecents;
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500169 private StatusBar mStatusBar;
Dave Mankoff613c7c62019-11-04 11:46:36 -0500170 private final Divider mDivider;
Dave Mankoffae3b4322019-11-05 19:48:24 -0500171 private final Optional<Recents> mRecentsOptional;
Jason Monk49fa0162017-01-11 09:21:56 -0500172 private WindowManager mWindowManager;
Dave Mankoffbcaca8a2019-10-31 18:04:08 -0400173 private final CommandQueue mCommandQueue;
Jason Monk49fa0162017-01-11 09:21:56 -0500174 private long mLastLockToAppLongPress;
175
176 private Locale mLocale;
177 private int mLayoutDirection;
178
Jorim Jaggi956ca412019-01-07 14:49:14 +0100179 /** @see android.view.WindowInsetsController#setSystemBarsAppearance(int) */
180 private @Appearance int mAppearance;
181
182 private boolean mTransientShown;
Winson Chung1aa24b92019-04-24 15:17:33 -0700183 private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
Jason Monk49fa0162017-01-11 09:21:56 -0500184 private LightBarController mLightBarController;
Charles Chen8c9a83f2018-12-18 17:44:10 +0800185 private AutoHideController mAutoHideController;
Jason Monk49fa0162017-01-11 09:21:56 -0500186
Matthew Ngdc79e5c2017-12-14 17:37:35 -0800187 private OverviewProxyService mOverviewProxyService;
188
Fabian Kozynskiff5e91f2019-09-24 15:38:08 -0400189 private final BroadcastDispatcher mBroadcastDispatcher;
190
Charles Chen54fce2c2019-03-13 18:17:29 +0800191 @VisibleForTesting
192 public int mDisplayId;
Charles Chen10ca70b2018-11-28 00:03:38 +0800193 private boolean mIsOnDefaultDisplay;
Jason Monk49fa0162017-01-11 09:21:56 -0500194 public boolean mHomeBlockedThisTouch;
shawnlin87af5382019-09-13 14:13:13 +0800195
196 /** Only for default display */
197 @Nullable
198 private AssistHandleViewController mAssistHandlerViewController;
Jason Monk49fa0162017-01-11 09:21:56 -0500199
Dave Mankoffea1953c2019-11-19 20:23:31 -0500200 private final Handler mHandler;
Charles Chen10ca70b2018-11-28 00:03:38 +0800201
Matthew Ng9c3bce52018-02-01 22:00:31 +0000202 private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
203 @Override
204 public void onConnectionChanged(boolean isConnected) {
Winson Chungf9e30272018-03-26 17:25:36 -0700205 mNavigationBarView.updateStates();
Matthew Ng9c3bce52018-02-01 22:00:31 +0000206 updateScreenPinningGestures();
Matthew Ngadd4c392019-03-01 16:02:31 -0800207
208 // Send the assistant availability upon connection
209 if (isConnected) {
Matthew Ngcf71ead2019-04-19 14:24:59 -0700210 sendAssistantAvailability(mAssistantAvailable);
Matthew Ngadd4c392019-03-01 16:02:31 -0800211 }
Matthew Ng9c3bce52018-02-01 22:00:31 +0000212 }
213
214 @Override
Matthew Ng2ea93b72018-03-14 19:43:18 +0000215 public void onQuickStepStarted() {
Mike Digman85a9bea2018-02-23 15:08:53 -0800216 // Use navbar dragging as a signal to hide the rotate button
Tracy Zhou24fd0282019-05-20 14:40:38 -0700217 mNavigationBarView.getRotationButtonController().setRotateSuggestionButtonState(false);
Matthew Ng90ef0632018-08-15 13:53:15 -0700218
219 // Hide the notifications panel when quick step starts
Heemin Seogba6337f2019-12-10 15:34:37 -0800220 mShadeController.collapsePanel(true /* animate */);
Matthew Ng9c3bce52018-02-01 22:00:31 +0000221 }
Matthew Ng8f25fb962018-01-16 17:17:24 -0800222
223 @Override
Matthew Ng42025e32019-02-20 15:02:58 -0800224 public void startAssistant(Bundle bundle) {
225 mAssistManager.startAssist(bundle);
226 }
227
228 @Override
Sunny Goyalc73ce702019-06-16 13:50:07 -0700229 public void onNavBarButtonAlphaChanged(float alpha, boolean animate) {
230 ButtonDispatcher buttonDispatcher = null;
231 if (QuickStepContract.isSwipeUpMode(mNavBarMode)) {
232 buttonDispatcher = mNavigationBarView.getBackButton();
233 } else if (QuickStepContract.isGesturalMode(mNavBarMode)) {
234 buttonDispatcher = mNavigationBarView.getHomeHandle();
235 }
236 if (buttonDispatcher != null) {
237 buttonDispatcher.setVisibility(alpha > 0 ? View.VISIBLE : View.INVISIBLE);
238 buttonDispatcher.setAlpha(alpha, animate);
Matthew Ngc83b9892018-08-21 16:31:13 -0700239 }
Matthew Ng96985e72018-05-08 15:46:13 -0700240 }
Matthew Ng9c3bce52018-02-01 22:00:31 +0000241 };
Mike Digman7d092772018-01-11 12:10:32 -0800242
Charles Chen10ca70b2018-11-28 00:03:38 +0800243 private final ContextButtonListener mRotationButtonListener = (button, visible) -> {
244 if (visible) {
245 // If the button will actually become visible and the navbar is about to hide,
246 // tell the statusbar to keep it around for longer
Charles Chen8c9a83f2018-12-18 17:44:10 +0800247 mAutoHideController.touchAutoHide();
Charles Chen10ca70b2018-11-28 00:03:38 +0800248 }
249 };
250
251 private final Runnable mAutoDim = () -> getBarTransitions().setAutoDim(true);
252
Matthew Ngadd4c392019-03-01 16:02:31 -0800253 private final ContentObserver mAssistContentObserver = new ContentObserver(
254 new Handler(Looper.getMainLooper())) {
255 @Override
256 public void onChange(boolean selfChange, Uri uri) {
257 boolean available = mAssistManager
258 .getAssistInfoForUser(UserHandle.USER_CURRENT) != null;
259 if (mAssistantAvailable != available) {
Matthew Ngcf71ead2019-04-19 14:24:59 -0700260 sendAssistantAvailability(available);
Matthew Ngadd4c392019-03-01 16:02:31 -0800261 mAssistantAvailable = available;
262 }
263 }
264 };
265
Jason Monk9424af72018-12-19 14:17:26 -0500266 @Inject
267 public NavigationBarFragment(AccessibilityManagerWrapper accessibilityManagerWrapper,
268 DeviceProvisionedController deviceProvisionedController, MetricsLogger metricsLogger,
Winson Chung1aa24b92019-04-24 15:17:33 -0700269 AssistManager assistManager, OverviewProxyService overviewProxyService,
Winson Chung9e572492019-06-07 10:48:45 -0700270 NavigationModeController navigationModeController,
Vinit Nayak59b114e62019-08-12 11:50:00 -0700271 StatusBarStateController statusBarStateController,
Fabian Kozynskiff5e91f2019-09-24 15:38:08 -0400272 SysUiState sysUiFlagsContainer,
Dave Mankoffbcaca8a2019-10-31 18:04:08 -0400273 BroadcastDispatcher broadcastDispatcher,
Dave Mankoff4dd47fa2019-11-07 10:44:48 -0500274 CommandQueue commandQueue, Divider divider,
Dave Mankoffea1953c2019-11-19 20:23:31 -0500275 Optional<Recents> recentsOptional, Lazy<StatusBar> statusBarLazy,
Heemin Seogba6337f2019-12-10 15:34:37 -0800276 ShadeController shadeController,
Dave Mankoff00e8a2f2019-12-18 16:59:49 -0500277 @Main Handler mainHandler) {
Jason Monk9424af72018-12-19 14:17:26 -0500278 mAccessibilityManagerWrapper = accessibilityManagerWrapper;
279 mDeviceProvisionedController = deviceProvisionedController;
Winson Chung9e572492019-06-07 10:48:45 -0700280 mStatusBarStateController = statusBarStateController;
Jason Monk9424af72018-12-19 14:17:26 -0500281 mMetricsLogger = metricsLogger;
282 mAssistManager = assistManager;
Vinit Nayak59b114e62019-08-12 11:50:00 -0700283 mSysUiFlagsContainer = sysUiFlagsContainer;
Dave Mankoff4dd47fa2019-11-07 10:44:48 -0500284 mStatusBarLazy = statusBarLazy;
Heemin Seogba6337f2019-12-10 15:34:37 -0800285 mShadeController = shadeController;
Matthew Ngadd4c392019-03-01 16:02:31 -0800286 mAssistantAvailable = mAssistManager.getAssistInfoForUser(UserHandle.USER_CURRENT) != null;
Jason Monk9424af72018-12-19 14:17:26 -0500287 mOverviewProxyService = overviewProxyService;
Winson Chung52d938d2019-09-25 16:50:05 -0700288 mNavigationModeController = navigationModeController;
Winson Chung1aa24b92019-04-24 15:17:33 -0700289 mNavBarMode = navigationModeController.addListener(this);
Fabian Kozynskiff5e91f2019-09-24 15:38:08 -0400290 mBroadcastDispatcher = broadcastDispatcher;
Dave Mankoffbcaca8a2019-10-31 18:04:08 -0400291 mCommandQueue = commandQueue;
Dave Mankoff613c7c62019-11-04 11:46:36 -0500292 mDivider = divider;
Dave Mankoffae3b4322019-11-05 19:48:24 -0500293 mRecentsOptional = recentsOptional;
Dave Mankoffea1953c2019-11-19 20:23:31 -0500294 mHandler = mainHandler;
Jason Monk9424af72018-12-19 14:17:26 -0500295 }
296
Jason Monk49fa0162017-01-11 09:21:56 -0500297 // ----- Fragment Lifecycle Callbacks -----
298
299 @Override
300 public void onCreate(@Nullable Bundle savedInstanceState) {
301 super.onCreate(savedInstanceState);
Jason Monk8e4e4cb2018-12-04 11:10:24 -0500302 mCommandQueue.observe(getLifecycle(), this);
Jason Monk49fa0162017-01-11 09:21:56 -0500303 mWindowManager = getContext().getSystemService(WindowManager.class);
304 mAccessibilityManager = getContext().getSystemService(AccessibilityManager.class);
Casey Burkhardtb9dcd662017-03-20 15:10:16 -0700305 mContentResolver = getContext().getContentResolver();
Casey Burkhardt74922c62017-02-13 12:43:16 -0800306 mMagnificationObserver = new MagnificationContentObserver(
307 getContext().getMainThreadHandler());
Casey Burkhardtb9dcd662017-03-20 15:10:16 -0700308 mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
Casey Burkhardt74922c62017-02-13 12:43:16 -0800309 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED), false,
Casey Burkhardt5d614402017-04-06 13:46:50 -0700310 mMagnificationObserver, UserHandle.USER_ALL);
Matthew Ngadd4c392019-03-01 16:02:31 -0800311 mContentResolver.registerContentObserver(
312 Settings.Secure.getUriFor(Settings.Secure.ASSISTANT),
313 false /* notifyForDescendants */, mAssistContentObserver, UserHandle.USER_ALL);
Casey Burkhardt74922c62017-02-13 12:43:16 -0800314
Jason Monk49fa0162017-01-11 09:21:56 -0500315 if (savedInstanceState != null) {
316 mDisabledFlags1 = savedInstanceState.getInt(EXTRA_DISABLE_STATE, 0);
Mike Digmandd2f49e2018-03-16 10:54:22 -0700317 mDisabledFlags2 = savedInstanceState.getInt(EXTRA_DISABLE2_STATE, 0);
Jorim Jaggi956ca412019-01-07 14:49:14 +0100318 mAppearance = savedInstanceState.getInt(EXTRA_APPEARANCE, 0);
319 mTransientShown = savedInstanceState.getBoolean(EXTRA_TRANSIENT_STATE, false);
Jason Monk49fa0162017-01-11 09:21:56 -0500320 }
Jason Monk9424af72018-12-19 14:17:26 -0500321 mAccessibilityManagerWrapper.addCallback(mAccessibilityListener);
Tetsutoki Shiozawae294e492019-01-11 18:46:28 +0900322
323 // Respect the latest disabled-flags.
324 mCommandQueue.recomputeDisableFlags(mDisplayId, false);
Jason Monk49fa0162017-01-11 09:21:56 -0500325 }
326
327 @Override
328 public void onDestroy() {
329 super.onDestroy();
Winson Chung52d938d2019-09-25 16:50:05 -0700330 mNavigationModeController.removeListener(this);
Jason Monk9424af72018-12-19 14:17:26 -0500331 mAccessibilityManagerWrapper.removeCallback(mAccessibilityListener);
Casey Burkhardtb9dcd662017-03-20 15:10:16 -0700332 mContentResolver.unregisterContentObserver(mMagnificationObserver);
Matthew Ngadd4c392019-03-01 16:02:31 -0800333 mContentResolver.unregisterContentObserver(mAssistContentObserver);
Jason Monk49fa0162017-01-11 09:21:56 -0500334 }
335
336 @Override
337 public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
338 Bundle savedInstanceState) {
339 return inflater.inflate(R.layout.navigation_bar, container, false);
340 }
341
342 @Override
343 public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
344 super.onViewCreated(view, savedInstanceState);
345 mNavigationBarView = (NavigationBarView) view;
Riddle Hsu19607772018-11-01 18:11:26 +0800346 final Display display = view.getDisplay();
347 // It may not have display when running unit test.
348 if (display != null) {
Charles Chen10ca70b2018-11-28 00:03:38 +0800349 mDisplayId = display.getDisplayId();
350 mIsOnDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
Riddle Hsu19607772018-11-01 18:11:26 +0800351 }
Jason Monk49fa0162017-01-11 09:21:56 -0500352
Dave Mankoff4dd47fa2019-11-07 10:44:48 -0500353 mNavigationBarView.setComponents(mStatusBarLazy.get().getPanel(), mAssistManager);
Matthew Ngf0f84542018-10-15 11:53:22 -0700354 mNavigationBarView.setDisabledFlags(mDisabledFlags1);
Jason Monk49fa0162017-01-11 09:21:56 -0500355 mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged);
356 mNavigationBarView.setOnTouchListener(this::onNavigationTouch);
357 if (savedInstanceState != null) {
358 mNavigationBarView.getLightTransitionsController().restoreState(savedInstanceState);
359 }
Matthew Ng94380652019-04-08 13:43:07 -0700360 mNavigationBarView.setNavigationIconHints(mNavigationIconHints);
Winson Chung2102ae82019-06-19 13:15:24 -0700361 mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
Jason Monk49fa0162017-01-11 09:21:56 -0500362
363 prepareNavigationBarView();
364 checkNavBarModes();
365
366 IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
367 filter.addAction(Intent.ACTION_SCREEN_ON);
Phil Weavera858c5f2018-04-26 13:27:30 -0700368 filter.addAction(Intent.ACTION_USER_SWITCHED);
Fabian Kozynskiff5e91f2019-09-24 15:38:08 -0400369 mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, Handler.getMain(),
370 UserHandle.ALL);
Siarhei Vishniakoud002a0a2017-06-05 22:44:37 +0100371 notifyNavigationBarScreenOn();
Winson Chung7e486912019-04-30 11:11:47 -0700372
Matthew Ng9c3bce52018-02-01 22:00:31 +0000373 mOverviewProxyService.addCallback(mOverviewProxyListener);
Winson Chunga7067002019-05-07 11:50:42 -0700374 updateSystemUiStateFlags(-1);
Matthew Ng761562d2018-09-17 11:13:21 -0700375
Riddle Hsu19607772018-11-01 18:11:26 +0800376 // Currently there is no accelerometer sensor on non-default display.
377 if (mIsOnDefaultDisplay) {
Tracy Zhou24fd0282019-05-20 14:40:38 -0700378 mNavigationBarView.getRotateSuggestionButton().setListener(mRotationButtonListener);
379
380 final RotationButtonController rotationButtonController =
381 mNavigationBarView.getRotationButtonController();
382 rotationButtonController.addRotationCallback(mRotationWatcher);
Matthew Ng761562d2018-09-17 11:13:21 -0700383
Riddle Hsu19607772018-11-01 18:11:26 +0800384 // Reset user rotation pref to match that of the WindowManager if starting in locked
385 // mode. This will automatically happen when switching from auto-rotate to locked mode.
Tracy Zhou24fd0282019-05-20 14:40:38 -0700386 if (display != null && rotationButtonController.isRotationLocked()) {
387 rotationButtonController.setRotationLockedAtAngle(display.getRotation());
Riddle Hsu19607772018-11-01 18:11:26 +0800388 }
389 } else {
390 mDisabledFlags2 |= StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS;
Matthew Ng761562d2018-09-17 11:13:21 -0700391 }
Riddle Hsu19607772018-11-01 18:11:26 +0800392 setDisabled2Flags(mDisabledFlags2);
shawnlin87af5382019-09-13 14:13:13 +0800393 if (mIsOnDefaultDisplay) {
394 mAssistHandlerViewController =
395 new AssistHandleViewController(mHandler, mNavigationBarView);
396 getBarTransitions().addDarkIntensityListener(mAssistHandlerViewController);
397 }
Jason Monk49fa0162017-01-11 09:21:56 -0500398 }
399
400 @Override
401 public void onDestroyView() {
402 super.onDestroyView();
Winson Chungb03d44d2018-09-18 12:42:45 -0700403 if (mNavigationBarView != null) {
shawnlin87af5382019-09-13 14:13:13 +0800404 if (mIsOnDefaultDisplay) {
405 mNavigationBarView.getBarTransitions()
406 .removeDarkIntensityListener(mAssistHandlerViewController);
407 mAssistHandlerViewController = null;
408 }
Winson Chungb03d44d2018-09-18 12:42:45 -0700409 mNavigationBarView.getBarTransitions().destroy();
410 mNavigationBarView.getLightTransitionsController().destroy(getContext());
411 }
Matthew Ng9c3bce52018-02-01 22:00:31 +0000412 mOverviewProxyService.removeCallback(mOverviewProxyListener);
Fabian Kozynskiff5e91f2019-09-24 15:38:08 -0400413 mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver);
Jason Monk49fa0162017-01-11 09:21:56 -0500414 }
415
416 @Override
417 public void onSaveInstanceState(Bundle outState) {
418 super.onSaveInstanceState(outState);
419 outState.putInt(EXTRA_DISABLE_STATE, mDisabledFlags1);
Mike Digmandd2f49e2018-03-16 10:54:22 -0700420 outState.putInt(EXTRA_DISABLE2_STATE, mDisabledFlags2);
Jorim Jaggi956ca412019-01-07 14:49:14 +0100421 outState.putInt(EXTRA_APPEARANCE, mAppearance);
422 outState.putBoolean(EXTRA_TRANSIENT_STATE, mTransientShown);
Jason Monk49fa0162017-01-11 09:21:56 -0500423 if (mNavigationBarView != null) {
424 mNavigationBarView.getLightTransitionsController().saveState(outState);
425 }
426 }
427
428 @Override
429 public void onConfigurationChanged(Configuration newConfig) {
430 super.onConfigurationChanged(newConfig);
431 final Locale locale = getContext().getResources().getConfiguration().locale;
432 final int ld = TextUtils.getLayoutDirectionFromLocale(locale);
433 if (!locale.equals(mLocale) || ld != mLayoutDirection) {
434 if (DEBUG) {
435 Log.v(TAG, String.format(
436 "config changed locale/LD: %s (%d) -> %s (%d)", mLocale, mLayoutDirection,
437 locale, ld));
438 }
439 mLocale = locale;
440 mLayoutDirection = ld;
441 refreshLayout(ld);
442 }
443 repositionNavigationBar();
444 }
445
446 @Override
447 public void dump(String prefix, FileDescriptor fd, PrintWriter pw, String[] args) {
448 if (mNavigationBarView != null) {
449 pw.print(" mNavigationBarWindowState=");
450 pw.println(windowStateToString(mNavigationBarWindowState));
451 pw.print(" mNavigationBarMode=");
452 pw.println(BarTransitions.modeToString(mNavigationBarMode));
453 dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions());
454 }
455
456 pw.print(" mNavigationBarView=");
457 if (mNavigationBarView == null) {
458 pw.println("null");
459 } else {
460 mNavigationBarView.dump(fd, pw, args);
461 }
462 }
463
464 // ----- CommandQueue Callbacks -----
465
466 @Override
Charles Chenf3d295c2018-11-30 18:15:21 +0800467 public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
Jason Monk49fa0162017-01-11 09:21:56 -0500468 boolean showImeSwitcher) {
Charles Chenf3d295c2018-11-30 18:15:21 +0800469 if (displayId != mDisplayId) {
470 return;
471 }
Jason Monk49fa0162017-01-11 09:21:56 -0500472 boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;
473 int hints = mNavigationIconHints;
Yohei Yukawa386f50e2018-03-14 13:03:42 -0700474 switch (backDisposition) {
475 case InputMethodService.BACK_DISPOSITION_DEFAULT:
476 case InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS:
477 case InputMethodService.BACK_DISPOSITION_WILL_DISMISS:
478 if (imeShown) {
479 hints |= NAVIGATION_HINT_BACK_ALT;
480 } else {
481 hints &= ~NAVIGATION_HINT_BACK_ALT;
482 }
483 break;
484 case InputMethodService.BACK_DISPOSITION_ADJUST_NOTHING:
485 hints &= ~NAVIGATION_HINT_BACK_ALT;
486 break;
Jason Monk49fa0162017-01-11 09:21:56 -0500487 }
488 if (showImeSwitcher) {
489 hints |= NAVIGATION_HINT_IME_SHOWN;
490 } else {
491 hints &= ~NAVIGATION_HINT_IME_SHOWN;
492 }
493 if (hints == mNavigationIconHints) return;
494
495 mNavigationIconHints = hints;
496
497 if (mNavigationBarView != null) {
498 mNavigationBarView.setNavigationIconHints(hints);
499 }
Charles Chen10ca70b2018-11-28 00:03:38 +0800500 checkBarModes();
Jason Monk49fa0162017-01-11 09:21:56 -0500501 }
502
503 @Override
Charles Chenf3d295c2018-11-30 18:15:21 +0800504 public void setWindowState(
505 int displayId, @WindowType int window, @WindowVisibleState int state) {
506 if (displayId == mDisplayId
507 && mNavigationBarView != null
Jason Monk49fa0162017-01-11 09:21:56 -0500508 && window == StatusBarManager.WINDOW_NAVIGATION_BAR
509 && mNavigationBarWindowState != state) {
510 mNavigationBarWindowState = state;
511 if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state));
Mike Digman5aeca792018-03-05 11:14:39 -0800512
Winson Chunga7067002019-05-07 11:50:42 -0700513 updateSystemUiStateFlags(-1);
Winson Chung2102ae82019-06-19 13:15:24 -0700514 mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
Jason Monk49fa0162017-01-11 09:21:56 -0500515 }
516 }
517
Mike Digman7d092772018-01-11 12:10:32 -0800518 @Override
Mike Digmane0777312018-01-19 12:41:51 -0800519 public void onRotationProposal(final int rotation, boolean isValid) {
Riddle Hsu19607772018-11-01 18:11:26 +0800520 final int winRotation = mNavigationBarView.getDisplay().getRotation();
Tracy Zhou24fd0282019-05-20 14:40:38 -0700521 final boolean rotateSuggestionsDisabled = RotationButtonController
Matthew Ng761562d2018-09-17 11:13:21 -0700522 .hasDisable2RotateSuggestionFlag(mDisabledFlags2);
Tracy Zhou24fd0282019-05-20 14:40:38 -0700523 final RotationButtonController rotationButtonController =
524 mNavigationBarView.getRotationButtonController();
525 final RotationButton rotationButton = rotationButtonController.getRotationButton();
526
Matthew Ng761562d2018-09-17 11:13:21 -0700527 if (RotationContextButton.DEBUG_ROTATION) {
Mike Digman3e33da62018-03-14 16:25:11 -0700528 Log.v(TAG, "onRotationProposal proposedRotation=" + Surface.rotationToString(rotation)
529 + ", winRotation=" + Surface.rotationToString(winRotation)
530 + ", isValid=" + isValid + ", mNavBarWindowState="
531 + StatusBarManager.windowStateToString(mNavigationBarWindowState)
Mike Digmandd2f49e2018-03-16 10:54:22 -0700532 + ", rotateSuggestionsDisabled=" + rotateSuggestionsDisabled
Tracy Zhou24fd0282019-05-20 14:40:38 -0700533 + ", isRotateButtonVisible=" + (mNavigationBarView == null ? "null"
534 : rotationButton.isVisible()));
Mike Digman3e33da62018-03-14 16:25:11 -0700535 }
536
Mike Digmandd2f49e2018-03-16 10:54:22 -0700537 // Respect the disabled flag, no need for action as flag change callback will handle hiding
538 if (rotateSuggestionsDisabled) return;
539
Tracy Zhou24fd0282019-05-20 14:40:38 -0700540 rotationButtonController.onRotationProposal(rotation, winRotation, isValid);
Mike Digman50752642018-02-15 13:36:09 -0800541 }
542
Jorim Jaggi956ca412019-01-07 14:49:14 +0100543 /** Restores the appearance and the transient saved state to {@link NavigationBarFragment}. */
544 public void restoreAppearanceAndTransientState() {
545 final int barMode = barMode(mTransientShown, mAppearance);
546 mNavigationBarMode = barMode;
Jason Monk49fa0162017-01-11 09:21:56 -0500547 checkNavBarModes();
Charles Chen8c9a83f2018-12-18 17:44:10 +0800548 mAutoHideController.touchAutoHide();
Andrii Kulian3ddd7de2018-10-10 00:33:19 -0700549
Jorim Jaggi956ca412019-01-07 14:49:14 +0100550 mLightBarController.onNavigationBarAppearanceChanged(mAppearance, true /* nbModeChanged */,
551 barMode, false /* navbarColorManagedByIme */);
Jason Monk49fa0162017-01-11 09:21:56 -0500552 }
553
554 @Override
Jorim Jaggi956ca412019-01-07 14:49:14 +0100555 public void onSystemBarAppearanceChanged(int displayId, @Appearance int appearance,
556 AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme) {
Charles Chenf3d295c2018-11-30 18:15:21 +0800557 if (displayId != mDisplayId) {
558 return;
559 }
Jason Monk49fa0162017-01-11 09:21:56 -0500560 boolean nbModeChanged = false;
Jorim Jaggi956ca412019-01-07 14:49:14 +0100561 if (mAppearance != appearance) {
562 mAppearance = appearance;
563 if (getView() == null) {
564 return;
Jason Monk49fa0162017-01-11 09:21:56 -0500565 }
Jorim Jaggi956ca412019-01-07 14:49:14 +0100566 nbModeChanged = updateBarMode(barMode(mTransientShown, appearance));
Jorim Jaggicb1b8482019-01-07 14:49:14 +0100567 }
Jorim Jaggi956ca412019-01-07 14:49:14 +0100568 mLightBarController.onNavigationBarAppearanceChanged(appearance, nbModeChanged,
569 mNavigationBarMode, navbarColorManagedByIme);
Jorim Jaggicb1b8482019-01-07 14:49:14 +0100570 }
571
Jorim Jaggi956ca412019-01-07 14:49:14 +0100572 @Override
Tiger Huang332793b2019-10-29 23:21:27 +0800573 public void showTransient(int displayId, @InternalInsetsType int[] types) {
Jorim Jaggi956ca412019-01-07 14:49:14 +0100574 if (displayId != mDisplayId) {
575 return;
Ioannis Ilkos8cca1412019-10-17 09:38:00 +0000576 }
Tiger Huang332793b2019-10-29 23:21:27 +0800577 if (!containsType(types, ITYPE_NAVIGATION_BAR)) {
Jorim Jaggi956ca412019-01-07 14:49:14 +0100578 return;
579 }
580 if (!mTransientShown) {
581 mTransientShown = true;
582 handleTransientChanged();
583 }
Ioannis Ilkos8cca1412019-10-17 09:38:00 +0000584 }
585
Jorim Jaggi956ca412019-01-07 14:49:14 +0100586 @Override
Tiger Huang332793b2019-10-29 23:21:27 +0800587 public void abortTransient(int displayId, @InternalInsetsType int[] types) {
Jorim Jaggi956ca412019-01-07 14:49:14 +0100588 if (displayId != mDisplayId) {
589 return;
590 }
Tiger Huang332793b2019-10-29 23:21:27 +0800591 if (!containsType(types, ITYPE_NAVIGATION_BAR)) {
Jorim Jaggi956ca412019-01-07 14:49:14 +0100592 return;
593 }
594 clearTransient();
595 }
596
597 void clearTransient() {
598 if (mTransientShown) {
599 mTransientShown = false;
600 handleTransientChanged();
601 }
602 }
603
604 private void handleTransientChanged() {
605 if (getView() == null) {
606 return;
607 }
608 if (mNavigationBarView != null) {
609 mNavigationBarView.onTransientStateChanged(mTransientShown);
610 }
611 final int barMode = barMode(mTransientShown, mAppearance);
612 if (updateBarMode(barMode)) {
613 mLightBarController.onNavigationBarModeChanged(barMode);
614 }
615 }
616
617 // Returns true if the bar mode is changed.
618 private boolean updateBarMode(int barMode) {
619 if (mNavigationBarMode != barMode) {
620 if (mNavigationBarMode == MODE_TRANSPARENT
621 || mNavigationBarMode == MODE_LIGHTS_OUT_TRANSPARENT) {
622 mNavigationBarView.hideRecentsOnboarding();
623 }
624 mNavigationBarMode = barMode;
625 checkNavBarModes();
626 mAutoHideController.touchAutoHide();
627 return true;
628 }
629 return false;
630 }
631
632 private static @TransitionMode int barMode(boolean isTransient, int appearance) {
Tiger Huang332793b2019-10-29 23:21:27 +0800633 final int lightsOutOpaque = APPEARANCE_LOW_PROFILE_BARS | APPEARANCE_OPAQUE_NAVIGATION_BARS;
Jorim Jaggi956ca412019-01-07 14:49:14 +0100634 if (isTransient) {
Charles Chen10ca70b2018-11-28 00:03:38 +0800635 return MODE_SEMI_TRANSPARENT;
Jorim Jaggi956ca412019-01-07 14:49:14 +0100636 } else if ((appearance & lightsOutOpaque) == lightsOutOpaque) {
Ioannis Ilkos8cca1412019-10-17 09:38:00 +0000637 return MODE_LIGHTS_OUT;
Jorim Jaggi956ca412019-01-07 14:49:14 +0100638 } else if ((appearance & APPEARANCE_LOW_PROFILE_BARS) != 0) {
639 return MODE_LIGHTS_OUT_TRANSPARENT;
Tiger Huang332793b2019-10-29 23:21:27 +0800640 } else if ((appearance & APPEARANCE_OPAQUE_NAVIGATION_BARS) != 0) {
Ioannis Ilkos8cca1412019-10-17 09:38:00 +0000641 return MODE_OPAQUE;
Jorim Jaggi956ca412019-01-07 14:49:14 +0100642 } else {
643 return MODE_TRANSPARENT;
Andrii Kulian3ddd7de2018-10-10 00:33:19 -0700644 }
Jason Monk49fa0162017-01-11 09:21:56 -0500645 }
646
647 @Override
Charles Chenf3d295c2018-11-30 18:15:21 +0800648 public void disable(int displayId, int state1, int state2, boolean animate) {
649 if (displayId != mDisplayId) {
650 return;
651 }
Mike Digmandd2f49e2018-03-16 10:54:22 -0700652 // Navigation bar flags are in both state1 and state2.
653 final int masked = state1 & (StatusBarManager.DISABLE_HOME
Jason Monk49fa0162017-01-11 09:21:56 -0500654 | StatusBarManager.DISABLE_RECENT
655 | StatusBarManager.DISABLE_BACK
656 | StatusBarManager.DISABLE_SEARCH);
657 if (masked != mDisabledFlags1) {
658 mDisabledFlags1 = masked;
Winson Chunga7067002019-05-07 11:50:42 -0700659 if (mNavigationBarView != null) {
660 mNavigationBarView.setDisabledFlags(state1);
661 }
Matthew Ng9c3bce52018-02-01 22:00:31 +0000662 updateScreenPinningGestures();
Jason Monk49fa0162017-01-11 09:21:56 -0500663 }
Mike Digmandd2f49e2018-03-16 10:54:22 -0700664
Riddle Hsu19607772018-11-01 18:11:26 +0800665 // Only default display supports rotation suggestions.
666 if (mIsOnDefaultDisplay) {
667 final int masked2 = state2 & (StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS);
668 if (masked2 != mDisabledFlags2) {
669 mDisabledFlags2 = masked2;
670 setDisabled2Flags(masked2);
671 }
Mike Digmandd2f49e2018-03-16 10:54:22 -0700672 }
673 }
674
675 private void setDisabled2Flags(int state2) {
676 // Method only called on change of disable2 flags
Evan Lairdb8b717f2018-10-25 14:08:32 -0400677 if (mNavigationBarView != null) {
Tracy Zhou24fd0282019-05-20 14:40:38 -0700678 mNavigationBarView.getRotationButtonController().onDisable2FlagChanged(state2);
Evan Lairdb8b717f2018-10-25 14:08:32 -0400679 }
Jason Monk49fa0162017-01-11 09:21:56 -0500680 }
681
Charles Chen10ca70b2018-11-28 00:03:38 +0800682 // ----- Internal stuff -----
Jason Monk49fa0162017-01-11 09:21:56 -0500683
684 private void refreshLayout(int layoutDirection) {
685 if (mNavigationBarView != null) {
686 mNavigationBarView.setLayoutDirection(layoutDirection);
687 }
688 }
689
690 private boolean shouldDisableNavbarGestures() {
Jason Monk297c04e2018-08-23 17:16:59 -0400691 return !mDeviceProvisionedController.isDeviceProvisioned()
Matthew Ngfee0b5b2018-02-21 15:38:21 -0800692 || (mDisabledFlags1 & StatusBarManager.DISABLE_SEARCH) != 0;
Jason Monk49fa0162017-01-11 09:21:56 -0500693 }
694
695 private void repositionNavigationBar() {
696 if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return;
697
698 prepareNavigationBarView();
699
700 mWindowManager.updateViewLayout((View) mNavigationBarView.getParent(),
701 ((View) mNavigationBarView.getParent()).getLayoutParams());
702 }
703
Matthew Ng9c3bce52018-02-01 22:00:31 +0000704 private void updateScreenPinningGestures() {
705 if (mNavigationBarView == null) {
706 return;
707 }
708
709 // Change the cancel pin gesture to home and back if recents button is invisible
710 boolean recentsVisible = mNavigationBarView.isRecentsButtonVisible();
Matthew Ng9c3bce52018-02-01 22:00:31 +0000711 ButtonDispatcher backButton = mNavigationBarView.getBackButton();
712 if (recentsVisible) {
Matthew Ng9c3bce52018-02-01 22:00:31 +0000713 backButton.setOnLongClickListener(this::onLongPressBackRecents);
714 } else {
Matthew Ng9c3bce52018-02-01 22:00:31 +0000715 backButton.setOnLongClickListener(this::onLongPressBackHome);
716 }
717 }
718
Siarhei Vishniakoud002a0a2017-06-05 22:44:37 +0100719 private void notifyNavigationBarScreenOn() {
Matthew Ngd0a73e72018-03-02 15:16:03 -0800720 mNavigationBarView.updateNavButtonIcons();
Jason Monk49fa0162017-01-11 09:21:56 -0500721 }
722
723 private void prepareNavigationBarView() {
724 mNavigationBarView.reorient();
725
726 ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton();
727 recentsButton.setOnClickListener(this::onRecentsClick);
728 recentsButton.setOnTouchListener(this::onRecentsTouch);
729 recentsButton.setLongClickable(true);
730 recentsButton.setOnLongClickListener(this::onLongPressBackRecents);
731
732 ButtonDispatcher backButton = mNavigationBarView.getBackButton();
733 backButton.setLongClickable(true);
Jason Monk49fa0162017-01-11 09:21:56 -0500734
735 ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
736 homeButton.setOnTouchListener(this::onHomeTouch);
Matthew Ngfee0b5b2018-02-21 15:38:21 -0800737 homeButton.setOnLongClickListener(this::onHomeLongClick);
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800738
739 ButtonDispatcher accessibilityButton = mNavigationBarView.getAccessibilityButton();
740 accessibilityButton.setOnClickListener(this::onAccessibilityClick);
741 accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick);
Phil Weaverdb9a7742017-04-18 08:15:06 -0700742 updateAccessibilityServicesState(mAccessibilityManager);
Mike Digman7d092772018-01-11 12:10:32 -0800743
Matthew Ng9c3bce52018-02-01 22:00:31 +0000744 updateScreenPinningGestures();
Jason Monk49fa0162017-01-11 09:21:56 -0500745 }
746
747 private boolean onHomeTouch(View v, MotionEvent event) {
748 if (mHomeBlockedThisTouch && event.getActionMasked() != MotionEvent.ACTION_DOWN) {
749 return true;
750 }
751 // If an incoming call is ringing, HOME is totally disabled.
752 // (The user is already on the InCallUI at this point,
753 // and his ONLY options are to answer or reject the call.)
754 switch (event.getAction()) {
755 case MotionEvent.ACTION_DOWN:
756 mHomeBlockedThisTouch = false;
757 TelecomManager telecomManager =
758 getContext().getSystemService(TelecomManager.class);
759 if (telecomManager != null && telecomManager.isRinging()) {
Dave Mankoff4dd47fa2019-11-07 10:44:48 -0500760 if (mStatusBarLazy.get().isKeyguardShowing()) {
Jason Monk49fa0162017-01-11 09:21:56 -0500761 Log.i(TAG, "Ignoring HOME; there's a ringing incoming call. " +
762 "No heads up");
763 mHomeBlockedThisTouch = true;
764 return true;
765 }
766 }
767 break;
768 case MotionEvent.ACTION_UP:
769 case MotionEvent.ACTION_CANCEL:
Dave Mankoff4dd47fa2019-11-07 10:44:48 -0500770 mStatusBarLazy.get().awakenDreams();
Jason Monk49fa0162017-01-11 09:21:56 -0500771 break;
772 }
773 return false;
774 }
775
776 private void onVerticalChanged(boolean isVertical) {
Dave Mankoff4dd47fa2019-11-07 10:44:48 -0500777 mStatusBarLazy.get().setQsScrimEnabled(!isVertical);
Jason Monk49fa0162017-01-11 09:21:56 -0500778 }
779
780 private boolean onNavigationTouch(View v, MotionEvent event) {
Charles Chen8c9a83f2018-12-18 17:44:10 +0800781 mAutoHideController.checkUserAutoHide(event);
Jason Monk49fa0162017-01-11 09:21:56 -0500782 return false;
783 }
784
Jason Monk865246d2017-01-19 08:27:01 -0500785 @VisibleForTesting
786 boolean onHomeLongClick(View v) {
Matthew Ng6ff33b72018-02-27 13:47:38 -0800787 if (!mNavigationBarView.isRecentsButtonVisible()
788 && ActivityManagerWrapper.getInstance().isScreenPinningActive()) {
Matthew Ngfee0b5b2018-02-21 15:38:21 -0800789 return onLongPressBackHome(v);
790 }
Jason Monk49fa0162017-01-11 09:21:56 -0500791 if (shouldDisableNavbarGestures()) {
792 return false;
793 }
Mike Digmanc94759d2018-01-23 11:01:21 -0800794 mMetricsLogger.action(MetricsEvent.ACTION_ASSIST_LONG_PRESS);
Govinda Wasserman24ff3062019-04-19 09:42:53 -0400795 Bundle args = new Bundle();
796 args.putInt(
797 AssistManager.INVOCATION_TYPE_KEY, AssistManager.INVOCATION_HOME_BUTTON_LONG_PRESS);
798 mAssistManager.startAssist(args);
Dave Mankoff4dd47fa2019-11-07 10:44:48 -0500799 mStatusBarLazy.get().awakenDreams();
Matthew Ngdc79e5c2017-12-14 17:37:35 -0800800
Jason Monk49fa0162017-01-11 09:21:56 -0500801 if (mNavigationBarView != null) {
802 mNavigationBarView.abortCurrentGesture();
803 }
804 return true;
805 }
806
807 // additional optimization when we have software system buttons - start loading the recent
808 // tasks on touch down
809 private boolean onRecentsTouch(View v, MotionEvent event) {
810 int action = event.getAction() & MotionEvent.ACTION_MASK;
811 if (action == MotionEvent.ACTION_DOWN) {
812 mCommandQueue.preloadRecentApps();
813 } else if (action == MotionEvent.ACTION_CANCEL) {
814 mCommandQueue.cancelPreloadRecentApps();
815 } else if (action == MotionEvent.ACTION_UP) {
816 if (!v.isPressed()) {
817 mCommandQueue.cancelPreloadRecentApps();
818 }
819 }
820 return false;
821 }
822
823 private void onRecentsClick(View v) {
824 if (LatencyTracker.isEnabled(getContext())) {
825 LatencyTracker.getInstance(getContext()).onActionStart(
826 LatencyTracker.ACTION_TOGGLE_RECENTS);
827 }
Dave Mankoff4dd47fa2019-11-07 10:44:48 -0500828 mStatusBarLazy.get().awakenDreams();
Jason Monk49fa0162017-01-11 09:21:56 -0500829 mCommandQueue.toggleRecentApps();
830 }
831
Matthew Ng9c3bce52018-02-01 22:00:31 +0000832 private boolean onLongPressBackHome(View v) {
833 return onLongPressNavigationButtons(v, R.id.back, R.id.home);
834 }
835
836 private boolean onLongPressBackRecents(View v) {
837 return onLongPressNavigationButtons(v, R.id.back, R.id.recent_apps);
838 }
839
Jason Monk49fa0162017-01-11 09:21:56 -0500840 /**
Matthew Ng9c3bce52018-02-01 22:00:31 +0000841 * This handles long-press of both back and recents/home. Back is the common button with
842 * combination of recents if it is visible or home if recents is invisible.
843 * They are handled together to capture them both being long-pressed
Jason Monk49fa0162017-01-11 09:21:56 -0500844 * at the same time to exit screen pinning (lock task).
845 *
Matthew Ng9c3bce52018-02-01 22:00:31 +0000846 * When accessibility mode is on, only a long-press from recents/home
Jason Monk49fa0162017-01-11 09:21:56 -0500847 * is required to exit.
848 *
849 * In all other circumstances we try to pass through long-press events
850 * for Back, so that apps can still use it. Which can be from two things.
851 * 1) Not currently in screen pinning (lock task).
Matthew Ng9c3bce52018-02-01 22:00:31 +0000852 * 2) Back is long-pressed without recents/home.
Jason Monk49fa0162017-01-11 09:21:56 -0500853 */
Matthew Ng9c3bce52018-02-01 22:00:31 +0000854 private boolean onLongPressNavigationButtons(View v, @IdRes int btnId1, @IdRes int btnId2) {
Jason Monk49fa0162017-01-11 09:21:56 -0500855 try {
856 boolean sendBackLongPress = false;
Wale Ogunwale04d9cb52018-04-30 13:55:07 -0700857 IActivityTaskManager activityManager = ActivityTaskManager.getService();
Jason Monk49fa0162017-01-11 09:21:56 -0500858 boolean touchExplorationEnabled = mAccessibilityManager.isTouchExplorationEnabled();
859 boolean inLockTaskMode = activityManager.isInLockTaskMode();
Winson Chunga3132982019-04-08 13:27:47 -0700860 boolean stopLockTaskMode = false;
861 try {
862 if (inLockTaskMode && !touchExplorationEnabled) {
863 long time = System.currentTimeMillis();
Matthew Ng9c3bce52018-02-01 22:00:31 +0000864
Winson Chunga3132982019-04-08 13:27:47 -0700865 // If we recently long-pressed the other button then they were
866 // long-pressed 'together'
867 if ((time - mLastLockToAppLongPress) < LOCK_TO_APP_GESTURE_TOLERENCE) {
868 stopLockTaskMode = true;
869 return true;
870 } else if (v.getId() == btnId1) {
871 ButtonDispatcher button = btnId2 == R.id.recent_apps
872 ? mNavigationBarView.getRecentsButton()
873 : mNavigationBarView.getHomeButton();
874 if (!button.getCurrentView().isPressed()) {
875 // If we aren't pressing recents/home right now then they presses
876 // won't be together, so send the standard long-press action.
877 sendBackLongPress = true;
878 }
879 }
880 mLastLockToAppLongPress = time;
881 } else {
882 // If this is back still need to handle sending the long-press event.
883 if (v.getId() == btnId1) {
Matthew Ng9c3bce52018-02-01 22:00:31 +0000884 sendBackLongPress = true;
Winson Chunga3132982019-04-08 13:27:47 -0700885 } else if (touchExplorationEnabled && inLockTaskMode) {
886 // When in accessibility mode a long press that is recents/home (not back)
887 // should stop lock task.
888 stopLockTaskMode = true;
889 return true;
890 } else if (v.getId() == btnId2) {
891 return btnId2 == R.id.recent_apps
892 ? onLongPressRecents()
893 : onHomeLongClick(
894 mNavigationBarView.getHomeButton().getCurrentView());
Matthew Ng9c3bce52018-02-01 22:00:31 +0000895 }
Jason Monk49fa0162017-01-11 09:21:56 -0500896 }
Winson Chunga3132982019-04-08 13:27:47 -0700897 } finally {
898 if (stopLockTaskMode) {
Benjamin Franza83859f2017-07-03 16:34:14 +0100899 activityManager.stopSystemLockTaskMode();
Jason Monk49fa0162017-01-11 09:21:56 -0500900 // When exiting refresh disabled flags.
Matthew Ngd0a73e72018-03-02 15:16:03 -0800901 mNavigationBarView.updateNavButtonIcons();
Jason Monk49fa0162017-01-11 09:21:56 -0500902 }
903 }
Winson Chunga3132982019-04-08 13:27:47 -0700904
Jason Monk49fa0162017-01-11 09:21:56 -0500905 if (sendBackLongPress) {
906 KeyButtonView keyButtonView = (KeyButtonView) v;
907 keyButtonView.sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
908 keyButtonView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
909 return true;
910 }
911 } catch (RemoteException e) {
912 Log.d(TAG, "Unable to reach activity manager", e);
913 }
914 return false;
915 }
916
917 private boolean onLongPressRecents() {
Dave Mankoffae3b4322019-11-05 19:48:24 -0500918 if (mRecentsOptional.isPresent() || !ActivityTaskManager.supportsMultiWindow(getContext())
Matthew Ng43db6d22017-06-27 15:29:39 -0700919 || !mDivider.getView().getSnapAlgorithm().isSplitScreenFeasible()
Winson Chung67f5c8b2018-09-24 12:09:19 -0700920 || ActivityManager.isLowRamDeviceStatic()
Winson Chung074c4342018-03-26 17:27:19 -0700921 // If we are connected to the overview service, then disable the recents button
922 || mOverviewProxyService.getProxy() != null) {
Jason Monk49fa0162017-01-11 09:21:56 -0500923 return false;
924 }
925
Dave Mankoff4dd47fa2019-11-07 10:44:48 -0500926 return mStatusBarLazy.get().toggleSplitScreenMode(MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS,
Jason Monk49fa0162017-01-11 09:21:56 -0500927 MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS);
928 }
929
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800930 private void onAccessibilityClick(View v) {
Jackal Guo8b729932018-10-19 18:02:51 +0800931 final Display display = v.getDisplay();
932 mAccessibilityManager.notifyAccessibilityButtonClicked(
933 display != null ? display.getDisplayId() : Display.DEFAULT_DISPLAY);
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800934 }
935
936 private boolean onAccessibilityLongClick(View v) {
Casey Burkhardt5e8b9802017-03-24 10:07:20 -0700937 Intent intent = new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON);
938 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
Casey Burkhardt5d614402017-04-06 13:46:50 -0700939 v.getContext().startActivityAsUser(intent, UserHandle.CURRENT);
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800940 return true;
941 }
942
Phil Weaverdb9a7742017-04-18 08:15:06 -0700943 private void updateAccessibilityServicesState(AccessibilityManager accessibilityManager) {
Sunny Goyal247eb892019-04-24 11:36:37 -0700944 boolean[] feedbackEnabled = new boolean[1];
Winson Chunga7067002019-05-07 11:50:42 -0700945 int a11yFlags = getA11yButtonState(feedbackEnabled);
Sunny Goyal247eb892019-04-24 11:36:37 -0700946
Winson Chunga7067002019-05-07 11:50:42 -0700947 boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
948 boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
Sunny Goyal247eb892019-04-24 11:36:37 -0700949 mNavigationBarView.setAccessibilityButtonState(clickable, longClickable);
Winson Chunga7067002019-05-07 11:50:42 -0700950
951 updateSystemUiStateFlags(a11yFlags);
952 }
953
954 public void updateSystemUiStateFlags(int a11yFlags) {
955 if (a11yFlags < 0) {
956 a11yFlags = getA11yButtonState(null);
957 }
958 boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
959 boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
Vinit Nayak59b114e62019-08-12 11:50:00 -0700960
961 mSysUiFlagsContainer.setFlag(SYSUI_STATE_A11Y_BUTTON_CLICKABLE, clickable)
962 .setFlag(SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE, longClickable)
963 .setFlag(SYSUI_STATE_NAV_BAR_HIDDEN, !isNavBarWindowVisible())
964 .commitUpdate(mDisplayId);
Sunny Goyal247eb892019-04-24 11:36:37 -0700965 }
966
967 /**
968 * Returns the system UI flags corresponding the the current accessibility button state
969 * @param outFeedbackEnabled if non-null, sets it to true if accessibility feedback is enabled.
970 */
971 public int getA11yButtonState(@Nullable boolean[] outFeedbackEnabled) {
Casey Burkhardt74922c62017-02-13 12:43:16 -0800972 int requestingServices = 0;
973 try {
Casey Burkhardt5d614402017-04-06 13:46:50 -0700974 if (Settings.Secure.getIntForUser(mContentResolver,
975 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED,
976 UserHandle.USER_CURRENT) == 1) {
Casey Burkhardt74922c62017-02-13 12:43:16 -0800977 requestingServices++;
978 }
979 } catch (Settings.SettingNotFoundException e) {
980 }
981
Mike Digman90402952018-01-22 16:05:51 -0800982 boolean feedbackEnabled = false;
Casey Burkhardt5d614402017-04-06 13:46:50 -0700983 // AccessibilityManagerService resolves services for the current user since the local
984 // AccessibilityManager is created from a Context with the INTERACT_ACROSS_USERS permission
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800985 final List<AccessibilityServiceInfo> services =
Sunny Goyal247eb892019-04-24 11:36:37 -0700986 mAccessibilityManager.getEnabledAccessibilityServiceList(
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800987 AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800988 for (int i = services.size() - 1; i >= 0; --i) {
989 AccessibilityServiceInfo info = services.get(i);
990 if ((info.flags & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0) {
991 requestingServices++;
992 }
Mike Digman90402952018-01-22 16:05:51 -0800993
994 if (info.feedbackType != 0 && info.feedbackType !=
995 AccessibilityServiceInfo.FEEDBACK_GENERIC) {
996 feedbackEnabled = true;
997 }
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800998 }
999
Sunny Goyal247eb892019-04-24 11:36:37 -07001000 if (outFeedbackEnabled != null) {
1001 outFeedbackEnabled[0] = feedbackEnabled;
1002 }
Mike Digman90402952018-01-22 16:05:51 -08001003
Sunny Goyal247eb892019-04-24 11:36:37 -07001004 return (requestingServices >= 1 ? SYSUI_STATE_A11Y_BUTTON_CLICKABLE : 0)
1005 | (requestingServices >= 2 ? SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE : 0);
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001006 }
1007
Matthew Ngcf71ead2019-04-19 14:24:59 -07001008 private void sendAssistantAvailability(boolean available) {
1009 if (mOverviewProxyService.getProxy() != null) {
1010 try {
1011 mOverviewProxyService.getProxy().onAssistantAvailable(available
Winson Chung1aa24b92019-04-24 15:17:33 -07001012 && QuickStepContract.isGesturalMode(mNavBarMode));
Matthew Ngcf71ead2019-04-19 14:24:59 -07001013 } catch (RemoteException e) {
1014 Log.w(TAG, "Unable to send assistant availability data to launcher");
1015 }
1016 }
1017 }
1018
Charles Chen10ca70b2018-11-28 00:03:38 +08001019 // ----- Methods that DisplayNavigationBarController talks to -----
1020
Charles Chen8c9a83f2018-12-18 17:44:10 +08001021 /** Applies auto dimming animation on navigation bar when touched. */
Charles Chen10ca70b2018-11-28 00:03:38 +08001022 public void touchAutoDim() {
1023 getBarTransitions().setAutoDim(false);
1024 mHandler.removeCallbacks(mAutoDim);
Winson Chung9e572492019-06-07 10:48:45 -07001025 int state = mStatusBarStateController.getState();
Charles Chen10ca70b2018-11-28 00:03:38 +08001026 if (state != StatusBarState.KEYGUARD && state != StatusBarState.SHADE_LOCKED) {
Charles Chen8c9a83f2018-12-18 17:44:10 +08001027 mHandler.postDelayed(mAutoDim, AUTODIM_TIMEOUT_MS);
Charles Chen10ca70b2018-11-28 00:03:38 +08001028 }
1029 }
Jason Monk49fa0162017-01-11 09:21:56 -05001030
Jason Monk49fa0162017-01-11 09:21:56 -05001031 public void setLightBarController(LightBarController lightBarController) {
1032 mLightBarController = lightBarController;
1033 mLightBarController.setNavigationBar(mNavigationBarView.getLightTransitionsController());
1034 }
1035
Charles Chen8c9a83f2018-12-18 17:44:10 +08001036 /** Sets {@link AutoHideController} to the navigation bar. */
1037 public void setAutoHideController(AutoHideController autoHideController) {
1038 mAutoHideController = autoHideController;
1039 mAutoHideController.setNavigationBar(this);
1040 }
1041
Jorim Jaggi956ca412019-01-07 14:49:14 +01001042 boolean isTransientShown() {
1043 return mTransientShown;
Jason Monk49fa0162017-01-11 09:21:56 -05001044 }
1045
Charles Chen10ca70b2018-11-28 00:03:38 +08001046 private void checkBarModes() {
1047 // We only have status bar on default display now.
1048 if (mIsOnDefaultDisplay) {
Dave Mankoff4dd47fa2019-11-07 10:44:48 -05001049 mStatusBarLazy.get().checkBarModes();
Charles Chen10ca70b2018-11-28 00:03:38 +08001050 } else {
1051 checkNavBarModes();
1052 }
1053 }
1054
Winson Chunga3132982019-04-08 13:27:47 -07001055 public boolean isNavBarWindowVisible() {
1056 return mNavigationBarWindowState == WINDOW_STATE_SHOWING;
1057 }
1058
Charles Chen10ca70b2018-11-28 00:03:38 +08001059 /**
1060 * Checks current navigation bar mode and make transitions.
1061 */
1062 public void checkNavBarModes() {
Dave Mankoff4dd47fa2019-11-07 10:44:48 -05001063 final boolean anim = mStatusBarLazy.get().isDeviceInteractive()
Charles Chen10ca70b2018-11-28 00:03:38 +08001064 && mNavigationBarWindowState != WINDOW_STATE_HIDDEN;
1065 mNavigationBarView.getBarTransitions().transitionTo(mNavigationBarMode, anim);
1066 }
1067
Winson Chung1aa24b92019-04-24 15:17:33 -07001068 @Override
1069 public void onNavigationModeChanged(int mode) {
1070 mNavBarMode = mode;
Winson Chung30c62602019-05-09 13:34:48 -07001071 updateScreenPinningGestures();
Winson Chung46d10aa2019-05-16 12:05:04 -07001072
1073 // Workaround for b/132825155, for secondary users, we currently don't receive configuration
1074 // changes on overlay package change since SystemUI runs for the system user. In this case,
1075 // trigger a new configuration change to ensure that the nav bar is updated in the same way.
1076 int userId = ActivityManagerWrapper.getInstance().getCurrentUserId();
1077 if (userId != UserHandle.USER_SYSTEM) {
1078 mHandler.post(() -> {
1079 FragmentHostManager fragmentHost = FragmentHostManager.get(mNavigationBarView);
1080 fragmentHost.reloadFragments();
1081 });
1082 }
Winson Chung1aa24b92019-04-24 15:17:33 -07001083 }
1084
Jason Monk49fa0162017-01-11 09:21:56 -05001085 public void disableAnimationsDuringHide(long delay) {
1086 mNavigationBarView.setLayoutTransitionsEnabled(false);
1087 mNavigationBarView.postDelayed(() -> mNavigationBarView.setLayoutTransitionsEnabled(true),
1088 delay + StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
1089 }
1090
shawnlin87af5382019-09-13 14:13:13 +08001091 @Nullable
1092 public AssistHandleViewController getAssistHandlerViewController() {
1093 return mAssistHandlerViewController;
1094 }
1095
Charles Chen10ca70b2018-11-28 00:03:38 +08001096 /**
1097 * Performs transitions on navigation bar.
1098 *
1099 * @param barMode transition bar mode.
1100 * @param animate shows animations if {@code true}.
1101 */
1102 public void transitionTo(@TransitionMode int barMode, boolean animate) {
1103 getBarTransitions().transitionTo(barMode, animate);
Jason Monk49fa0162017-01-11 09:21:56 -05001104 }
1105
James O'Leary4335c702019-05-29 12:38:51 -04001106 public NavigationBarTransitions getBarTransitions() {
Charles Chen10ca70b2018-11-28 00:03:38 +08001107 return mNavigationBarView.getBarTransitions();
Jason Monk49fa0162017-01-11 09:21:56 -05001108 }
1109
1110 public void finishBarAnimations() {
1111 mNavigationBarView.getBarTransitions().finishAnimations();
1112 }
1113
Jason Monk91e587e2017-04-13 13:41:23 -04001114 private final AccessibilityServicesStateChangeListener mAccessibilityListener =
1115 this::updateAccessibilityServicesState;
1116
Casey Burkhardt74922c62017-02-13 12:43:16 -08001117 private class MagnificationContentObserver extends ContentObserver {
1118
1119 public MagnificationContentObserver(Handler handler) {
1120 super(handler);
1121 }
1122
1123 @Override
1124 public void onChange(boolean selfChange) {
Phil Weaverdb9a7742017-04-18 08:15:06 -07001125 NavigationBarFragment.this.updateAccessibilityServicesState(mAccessibilityManager);
Casey Burkhardt74922c62017-02-13 12:43:16 -08001126 }
1127 }
1128
Matthew Ng761562d2018-09-17 11:13:21 -07001129 private final Consumer<Integer> mRotationWatcher = rotation -> {
1130 if (mNavigationBarView != null
1131 && mNavigationBarView.needsReorient(rotation)) {
1132 repositionNavigationBar();
Mike Digman85ff7fa2018-01-23 14:59:52 -08001133 }
Jason Monk49fa0162017-01-11 09:21:56 -05001134 };
1135
1136 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
1137 @Override
1138 public void onReceive(Context context, Intent intent) {
1139 String action = intent.getAction();
Siarhei Vishniakoud002a0a2017-06-05 22:44:37 +01001140 if (Intent.ACTION_SCREEN_OFF.equals(action)
1141 || Intent.ACTION_SCREEN_ON.equals(action)) {
1142 notifyNavigationBarScreenOn();
Vinit Nayak3f35db52019-08-08 17:31:48 -07001143 mNavigationBarView.onScreenStateChanged(Intent.ACTION_SCREEN_ON.equals(action));
Jason Monk49fa0162017-01-11 09:21:56 -05001144 }
Phil Weavera858c5f2018-04-26 13:27:30 -07001145 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
1146 // The accessibility settings may be different for the new user
1147 updateAccessibilityServicesState(mAccessibilityManager);
Charles Chen10ca70b2018-11-28 00:03:38 +08001148 }
Jason Monk49fa0162017-01-11 09:21:56 -05001149 }
1150 };
1151
1152 public static View create(Context context, FragmentListener listener) {
1153 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
Charles Chenb6aff432018-11-16 20:25:46 +08001154 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
1155 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
Jason Monk49fa0162017-01-11 09:21:56 -05001156 WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
1157 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
1158 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
1159 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
1160 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
1161 | WindowManager.LayoutParams.FLAG_SLIPPERY,
1162 PixelFormat.TRANSLUCENT);
1163 lp.token = new Binder();
Charles Chen10ca70b2018-11-28 00:03:38 +08001164 lp.setTitle("NavigationBar" + context.getDisplayId());
Phil Weaver8583ae82018-02-13 11:01:24 -08001165 lp.accessibilityTitle = context.getString(R.string.nav_bar);
Jason Monk49fa0162017-01-11 09:21:56 -05001166 lp.windowAnimations = 0;
Peiyong Lin75045382019-03-04 19:22:33 -08001167 lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
Jason Monk49fa0162017-01-11 09:21:56 -05001168
1169 View navigationBarView = LayoutInflater.from(context).inflate(
1170 R.layout.navigation_bar_window, null);
1171
1172 if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + navigationBarView);
1173 if (navigationBarView == null) return null;
1174
Jason Monk9424af72018-12-19 14:17:26 -05001175 final NavigationBarFragment fragment = FragmentHostManager.get(navigationBarView)
1176 .create(NavigationBarFragment.class);
Riddle Hsu19607772018-11-01 18:11:26 +08001177 navigationBarView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
1178 @Override
1179 public void onViewAttachedToWindow(View v) {
1180 final FragmentHostManager fragmentHost = FragmentHostManager.get(v);
1181 fragmentHost.getFragmentManager().beginTransaction()
1182 .replace(R.id.navigation_bar_frame, fragment, TAG)
1183 .commit();
1184 fragmentHost.addTagListener(TAG, listener);
1185 }
1186
1187 @Override
1188 public void onViewDetachedFromWindow(View v) {
1189 FragmentHostManager.removeAndDestroy(v);
1190 }
1191 });
Jason Monk49fa0162017-01-11 09:21:56 -05001192 context.getSystemService(WindowManager.class).addView(navigationBarView, lp);
Jason Monk49fa0162017-01-11 09:21:56 -05001193 return navigationBarView;
1194 }
lumark7570cac2019-03-07 22:14:38 +08001195
1196 @VisibleForTesting
1197 int getNavigationIconHints() {
1198 return mNavigationIconHints;
1199 }
Jason Monk49fa0162017-01-11 09:21:56 -05001200}