blob: e83b159c4911a142f50b6a64b133b1eb5e31dea6 [file] [log] [blame]
Daniel Sandler8956dbb2011-04-22 07:55:02 -04001/*
2 * Copyright (C) 2008 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.phone;
18
Hongwei Wang0e625742019-08-14 14:55:27 -070019import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
20
Winson Chunga7067002019-05-07 11:50:42 -070021import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
Winson Chunga3132982019-04-08 13:27:47 -070022import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
Winson Chunga7067002019-05-07 11:50:42 -070023import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
Winson Chung5b6a1fe2019-07-26 16:38:08 -070024import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
Winson Chunga7067002019-05-07 11:50:42 -070025import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
Winson Chungcb6454e2019-07-23 09:58:47 -070026import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SEARCH_DISABLED;
Tracy Zhou24fd0282019-05-20 14:40:38 -070027import static com.android.systemui.shared.system.QuickStepContract.isGesturalMode;
Winson Chung775d2872019-03-27 14:14:01 -070028import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
Vinit Nayak3f35db52019-08-08 17:31:48 -070029import static com.android.systemui.util.Utils.isGesturalModeOnDefaultDisplay;
Winson Chungc4e06202018-02-13 10:37:35 -080030
John Spurlock1bbd49d2012-10-19 11:09:32 -040031import android.animation.LayoutTransition;
John Spurlock56d007b2013-10-28 18:40:56 -040032import android.animation.LayoutTransition.TransitionListener;
33import android.animation.ObjectAnimator;
Matthew Ngca4592b2018-08-06 14:12:37 -070034import android.animation.PropertyValuesHolder;
John Spurlock56d007b2013-10-28 18:40:56 -040035import android.animation.TimeInterpolator;
36import android.animation.ValueAnimator;
Jorim Jaggi40db0292016-06-27 17:58:03 -070037import android.annotation.DrawableRes;
Vinit Nayakd2fe92f2020-06-04 13:12:02 -070038import android.annotation.Nullable;
Daniel Sandler328310c2011-09-23 15:56:52 -040039import android.app.StatusBarManager;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040040import android.content.Context;
Selim Cinek17a327a2014-08-25 15:03:48 +020041import android.content.res.Configuration;
Matthew Nga8f24262017-12-19 11:54:24 -080042import android.graphics.Canvas;
Jeff Browna8b9def2012-07-23 14:22:49 -070043import android.graphics.Point;
Daniel Sandler48852952011-12-01 14:34:23 -050044import android.graphics.Rect;
Sunny Goyalaac6c882019-02-11 11:57:58 -080045import android.graphics.Region;
46import android.graphics.Region.Op;
Matthew Ng44b14502018-05-04 11:10:14 -070047import android.os.Bundle;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040048import android.util.AttributeSet;
John Spurlockcd686b52013-06-05 10:13:46 -040049import android.util.Log;
Jason Monka2081822016-01-18 14:41:03 -050050import android.util.SparseArray;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040051import android.view.Display;
Daniel Sandler1d4d30a2011-04-28 12:35:29 -040052import android.view.MotionEvent;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040053import android.view.Surface;
John Spurlockde84f0e2013-06-12 12:41:00 -040054import android.view.View;
John Spurlock1bbd49d2012-10-19 11:09:32 -040055import android.view.ViewGroup;
Tracy Zhouefc34662019-04-22 13:37:12 -070056import android.view.ViewTreeObserver.InternalInsetsInfo;
57import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
Adrian Roos7e58a082018-03-09 16:40:56 +010058import android.view.WindowInsets;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040059import android.view.WindowManager;
Matthew Ng44b14502018-05-04 11:10:14 -070060import android.view.accessibility.AccessibilityNodeInfo;
61import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
Jason Monkf1ff2092014-04-29 16:50:53 -040062import android.view.inputmethod.InputMethodManager;
Jason Monk86bc3312016-08-16 13:17:56 -040063import android.widget.FrameLayout;
Jason Monk67e6c802016-08-30 14:09:21 -040064
Jeff Chang2aaa91a2018-11-08 18:04:16 +080065import com.android.internal.annotations.VisibleForTesting;
Jason Monkde850bb2017-02-01 19:26:30 -050066import com.android.systemui.Dependency;
Matthew Ngca4592b2018-08-06 14:12:37 -070067import com.android.systemui.Interpolators;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040068import com.android.systemui.R;
shawnlin2624bec2019-10-07 16:43:21 +080069import com.android.systemui.assist.AssistHandleViewController;
Vinit Nayak59b114e62019-08-12 11:50:00 -070070import com.android.systemui.model.SysUiState;
Gus Prevasab336792018-11-14 13:52:20 -050071import com.android.systemui.recents.OverviewProxyService;
Matthew Ng44b14502018-05-04 11:10:14 -070072import com.android.systemui.recents.Recents;
Tony Wickham05c1f852018-02-06 12:32:54 -080073import com.android.systemui.recents.RecentsOnboarding;
Andy Wickham20297012019-11-06 14:56:26 -080074import com.android.systemui.shared.plugins.PluginManager;
Matthew Ng87cbf342018-02-15 12:21:18 -080075import com.android.systemui.shared.system.ActivityManagerWrapper;
Winson Chunge108b672019-03-06 16:11:28 -080076import com.android.systemui.shared.system.QuickStepContract;
Matthew Ng84db1612018-04-17 16:48:21 -070077import com.android.systemui.shared.system.WindowManagerWrapper;
Evan Roskyaf9f27c2020-02-18 18:58:35 +000078import com.android.systemui.stackdivider.Divider;
Dave Mankoffbcaca8a2019-10-31 18:04:08 -040079import com.android.systemui.statusbar.CommandQueue;
shawnlin2624bec2019-10-07 16:43:21 +080080import com.android.systemui.statusbar.NavigationBarController;
Daniel Sandlerc26185b2012-08-29 15:49:53 -040081import com.android.systemui.statusbar.policy.DeadZone;
Jorim Jaggi40db0292016-06-27 17:58:03 -070082import com.android.systemui.statusbar.policy.KeyButtonDrawable;
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070083
John Spurlockde84f0e2013-06-12 12:41:00 -040084import java.io.FileDescriptor;
85import java.io.PrintWriter;
Jason Monk32e3bb52017-07-27 12:35:41 -040086import java.util.function.Consumer;
John Spurlockde84f0e2013-06-12 12:41:00 -040087
Matthew Nge0d5ccd32019-05-08 15:13:22 -070088public class NavigationBarView extends FrameLayout implements
Winson Chung1aa24b92019-04-24 15:17:33 -070089 NavigationModeController.ModeChangedListener {
Daniel Sandler60ee2562011-07-22 12:34:33 -040090 final static boolean DEBUG = false;
Adrian Roosa98b32c2016-08-11 10:41:08 -070091 final static String TAG = "StatusBar/NavBarView";
Daniel Sandler60ee2562011-07-22 12:34:33 -040092
Daniel Sandlerc3fc3222012-10-25 13:28:33 -040093 // slippery nav bar when everything is disabled, e.g. during setup
John Spurlock7edfbca2013-09-14 11:58:55 -040094 final static boolean SLIPPERY_WHEN_DISABLED = true;
Daniel Sandlerc3fc3222012-10-25 13:28:33 -040095
Justin Paupore01915a12016-09-28 17:41:26 -070096 final static boolean ALTERNATE_CAR_MODE_UI = false;
Vinit Nayak3f35db52019-08-08 17:31:48 -070097 private final RegionSamplingHelper mRegionSamplingHelper;
98 private final int mNavColorSampleMargin;
Vinit Nayak59b114e62019-08-12 11:50:00 -070099 private final SysUiState mSysUiFlagContainer;
Andy Wickham20297012019-11-06 14:56:26 -0800100 private final PluginManager mPluginManager;
Justin Paupore01915a12016-09-28 17:41:26 -0700101
Daniel Sandler5c8da942011-06-28 00:29:04 -0400102 View mCurrentView = null;
Charles Chenaa94d95b2019-02-19 14:18:19 +0800103 private View mVertical;
104 private View mHorizontal;
Daniel Sandler60ee2562011-07-22 12:34:33 -0400105
Charles Chenaa94d95b2019-02-19 14:18:19 +0800106 /** Indicates that navigation bar is vertical. */
107 private boolean mIsVertical;
Adrian Roos090b7d82016-08-02 18:36:12 -0700108 private int mCurrentRotation = -1;
Daniel Sandler60ee2562011-07-22 12:34:33 -0400109
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800110 boolean mLongClickableAccessibilityButton;
Daniel Sandler6da2b762011-09-14 16:04:59 -0400111 int mDisabledFlags = 0;
Daniel Sandler328310c2011-09-23 15:56:52 -0400112 int mNavigationIconHints = 0;
Vinit Nayak3f35db52019-08-08 17:31:48 -0700113 private int mNavBarMode;
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400114
Winson Chungc4e06202018-02-13 10:37:35 -0800115 private Rect mHomeButtonBounds = new Rect();
116 private Rect mBackButtonBounds = new Rect();
Matthew Ng8a8c89c2018-03-01 13:21:43 -0800117 private Rect mRecentsButtonBounds = new Rect();
Winson Chung8079af72018-05-10 11:12:55 -0700118 private Rect mRotationButtonBounds = new Rect();
Sunny Goyalaac6c882019-02-11 11:57:58 -0800119 private final Region mActiveRegion = new Region();
Winson Chungc4e06202018-02-13 10:37:35 -0800120 private int[] mTmpPosition = new int[2];
121
Matthew Ngeb5ce832018-05-15 17:50:37 -0700122 private KeyButtonDrawable mBackIcon;
Matthew Ngec5b8412018-08-22 10:45:08 -0700123 private KeyButtonDrawable mHomeDefaultIcon;
Jorim Jaggi40db0292016-06-27 17:58:03 -0700124 private KeyButtonDrawable mRecentIcon;
125 private KeyButtonDrawable mDockedIcon;
Fabrice Di Meglio18d98242013-01-17 10:57:40 -0800126
Sunny Goyal38412952020-04-17 11:35:37 -0700127 private EdgeBackGestureHandler mEdgeBackGestureHandler;
Matthew Ng603b3292018-03-30 17:15:39 -0700128 private final DeadZone mDeadZone;
Matthew Ng1e14e962018-05-03 12:51:43 -0700129 private boolean mDeadZoneConsuming = false;
John Spurlock89835dd2013-08-16 15:06:51 -0400130 private final NavigationBarTransitions mBarTransitions;
Matthew Ngdc79e5c2017-12-14 17:37:35 -0800131 private final OverviewProxyService mOverviewProxyService;
Jim Millere898ac52012-04-06 17:10:57 -0700132
John Spurlock56d007b2013-10-28 18:40:56 -0400133 // performs manual animation in sync with layout transitions
134 private final NavTransitionListener mTransitionListener = new NavTransitionListener();
135
Jorim Jaggif4797922014-08-04 22:49:41 +0200136 private OnVerticalChangedListener mOnVerticalChangedListener;
Jorim Jaggi37c11802015-08-18 20:27:54 -0700137 private boolean mLayoutTransitionsEnabled = true;
138 private boolean mWakeAndUnlocking;
Justin Paupore01915a12016-09-28 17:41:26 -0700139 private boolean mUseCarModeUi = false;
140 private boolean mInCarMode = false;
Jorim Jaggid30d95d2016-02-17 20:27:22 -0800141 private boolean mDockedStackExists;
Matthew Ngf03c3a62019-04-03 13:52:57 -0700142 private boolean mImeVisible;
Jorim Jaggif4797922014-08-04 22:49:41 +0200143
Felipe Leme15f915c2016-10-31 12:47:15 -0700144 private final SparseArray<ButtonDispatcher> mButtonDispatchers = new SparseArray<>();
Matthew Ng25593cc2018-09-12 16:05:41 -0700145 private final ContextualButtonGroup mContextualButtonGroup;
Winsonfde2e6a2016-03-22 16:03:10 -0700146 private Configuration mConfiguration;
Matthew Ng8c056c12018-10-15 15:16:46 -0700147 private Configuration mTmpLastConfiguration;
Jason Monka2081822016-01-18 14:41:03 -0500148
Adrian Roosdb12b152016-07-12 15:38:55 -0700149 private NavigationBarInflaterView mNavigationInflaterView;
Tony Wickham05c1f852018-02-06 12:32:54 -0800150 private RecentsOnboarding mRecentsOnboarding;
Dave Mankoffaf8163f2020-01-08 14:24:35 -0500151 private NotificationPanelViewController mPanelView;
Tracy Zhou24fd0282019-05-20 14:40:38 -0700152 private FloatingRotationButton mFloatingRotationButton;
153 private RotationButtonController mRotationButtonController;
Adrian Roosdb12b152016-07-12 15:38:55 -0700154
Matthew Ng20136e62018-05-30 12:20:31 -0700155 /**
156 * Helper that is responsible for showing the right toast when a disallowed activity operation
157 * occurred. In pinned mode, we show instructions on how to break out of this mode, whilst in
158 * fully locked mode we only show that unlocking is blocked.
159 */
160 private ScreenPinningNotify mScreenPinningNotify;
Vinit Nayak3f35db52019-08-08 17:31:48 -0700161 private Rect mSamplingBounds = new Rect();
Vinit Nayakd2fe92f2020-06-04 13:12:02 -0700162 /**
163 * When quickswitching between apps of different orientations, we draw a secondary home handle
164 * in the position of the first app's orientation. This rect represents the region of that
165 * home handle so we can apply the correct light/dark luma on that.
166 * @see {@link NavigationBarFragment#mOrientationHandle}
167 */
168 @Nullable
169 private Rect mOrientedHandleSamplingRegion;
Matthew Ng20136e62018-05-30 12:20:31 -0700170
John Spurlock56d007b2013-10-28 18:40:56 -0400171 private class NavTransitionListener implements TransitionListener {
172 private boolean mBackTransitioning;
173 private boolean mHomeAppearing;
174 private long mStartDelay;
175 private long mDuration;
176 private TimeInterpolator mInterpolator;
177
178 @Override
179 public void startTransition(LayoutTransition transition, ViewGroup container,
180 View view, int transitionType) {
181 if (view.getId() == R.id.back) {
182 mBackTransitioning = true;
183 } else if (view.getId() == R.id.home && transitionType == LayoutTransition.APPEARING) {
184 mHomeAppearing = true;
185 mStartDelay = transition.getStartDelay(transitionType);
186 mDuration = transition.getDuration(transitionType);
187 mInterpolator = transition.getInterpolator(transitionType);
188 }
189 }
190
191 @Override
192 public void endTransition(LayoutTransition transition, ViewGroup container,
193 View view, int transitionType) {
194 if (view.getId() == R.id.back) {
195 mBackTransitioning = false;
196 } else if (view.getId() == R.id.home && transitionType == LayoutTransition.APPEARING) {
197 mHomeAppearing = false;
198 }
199 }
200
201 public void onBackAltCleared() {
Jason Monka2081822016-01-18 14:41:03 -0500202 ButtonDispatcher backButton = getBackButton();
Anthony Chenada13042016-01-19 16:57:20 -0800203
John Spurlock56d007b2013-10-28 18:40:56 -0400204 // When dismissing ime during unlock, force the back button to run the same appearance
205 // animation as home (if we catch this condition early enough).
Jason Monka2081822016-01-18 14:41:03 -0500206 if (!mBackTransitioning && backButton.getVisibility() == VISIBLE
207 && mHomeAppearing && getHomeButton().getAlpha() == 0) {
John Spurlock56d007b2013-10-28 18:40:56 -0400208 getBackButton().setAlpha(0);
Anthony Chenada13042016-01-19 16:57:20 -0800209 ValueAnimator a = ObjectAnimator.ofFloat(backButton, "alpha", 0, 1);
John Spurlock56d007b2013-10-28 18:40:56 -0400210 a.setStartDelay(mStartDelay);
211 a.setDuration(mDuration);
212 a.setInterpolator(mInterpolator);
213 a.start();
214 }
215 }
216 }
217
Jason Monkf1ff2092014-04-29 16:50:53 -0400218 private final OnClickListener mImeSwitcherClickListener = new OnClickListener() {
219 @Override
220 public void onClick(View view) {
lumark0b05f9e2018-11-26 15:09:06 +0800221 mContext.getSystemService(InputMethodManager.class).showInputMethodPickerFromSystem(
222 true /* showAuxiliarySubtypes */, getContext().getDisplayId());
Jason Monkf1ff2092014-04-29 16:50:53 -0400223 }
224 };
225
Dave Mankoff6c64d1f2019-11-07 17:27:50 -0500226 private final AccessibilityDelegate mQuickStepAccessibilityDelegate =
227 new AccessibilityDelegate() {
228 private AccessibilityAction mToggleOverviewAction;
Matthew Ng44b14502018-05-04 11:10:14 -0700229
Dave Mankoff6c64d1f2019-11-07 17:27:50 -0500230 @Override
231 public void onInitializeAccessibilityNodeInfo(View host,
232 AccessibilityNodeInfo info) {
233 super.onInitializeAccessibilityNodeInfo(host, info);
234 if (mToggleOverviewAction == null) {
235 mToggleOverviewAction = new AccessibilityAction(
236 R.id.action_toggle_overview, getContext().getString(
237 R.string.quick_step_accessibility_toggle_overview));
238 }
239 info.addAction(mToggleOverviewAction);
240 }
Matthew Ng44b14502018-05-04 11:10:14 -0700241
Dave Mankoff6c64d1f2019-11-07 17:27:50 -0500242 @Override
243 public boolean performAccessibilityAction(View host, int action, Bundle args) {
244 if (action == R.id.action_toggle_overview) {
245 Dependency.get(Recents.class).toggleRecentApps();
246 } else {
247 return super.performAccessibilityAction(host, action, args);
248 }
249 return true;
250 }
251 };
Matthew Ng44b14502018-05-04 11:10:14 -0700252
Tracy Zhouefc34662019-04-22 13:37:12 -0700253 private final OnComputeInternalInsetsListener mOnComputeInternalInsetsListener = info -> {
254 // When the nav bar is in 2-button or 3-button mode, or when IME is visible in fully
255 // gestural mode, the entire nav bar should be touchable.
Sunny Goyal38412952020-04-17 11:35:37 -0700256 if (!mEdgeBackGestureHandler.isHandlingGestures() || mImeVisible) {
Tracy Zhouefc34662019-04-22 13:37:12 -0700257 info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
258 return;
259 }
Winson Chungd882ce12019-06-05 09:57:01 -0700260
Tracy Zhouefc34662019-04-22 13:37:12 -0700261 info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
Winson Chungd882ce12019-06-05 09:57:01 -0700262 ButtonDispatcher imeSwitchButton = getImeSwitchButton();
263 if (imeSwitchButton.getVisibility() == VISIBLE) {
264 // If the IME is not up, but the ime switch button is visible, then make sure that
265 // button is touchable
266 int[] loc = new int[2];
267 View buttonView = imeSwitchButton.getCurrentView();
268 buttonView.getLocationInWindow(loc);
269 info.touchableRegion.set(loc[0], loc[1], loc[0] + buttonView.getWidth(),
270 loc[1] + buttonView.getHeight());
271 return;
272 }
Tracy Zhou24fd0282019-05-20 14:40:38 -0700273 info.touchableRegion.setEmpty();
Tracy Zhouefc34662019-04-22 13:37:12 -0700274 };
275
John Spurlocke932e302013-08-12 10:16:29 -0400276 public NavigationBarView(Context context, AttributeSet attrs) {
277 super(context, attrs);
278
Charles Chenaa94d95b2019-02-19 14:18:19 +0800279 mIsVertical = false;
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800280 mLongClickableAccessibilityButton = false;
Tracy Zhouefc34662019-04-22 13:37:12 -0700281 mNavBarMode = Dependency.get(NavigationModeController.class).addListener(this);
Tracy Zhou24fd0282019-05-20 14:40:38 -0700282 boolean isGesturalMode = isGesturalMode(mNavBarMode);
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800283
Vinit Nayak59b114e62019-08-12 11:50:00 -0700284 mSysUiFlagContainer = Dependency.get(SysUiState.class);
Andy Wickham20297012019-11-06 14:56:26 -0800285 mPluginManager = Dependency.get(PluginManager.class);
Matthew Ng25593cc2018-09-12 16:05:41 -0700286 // Set up the context group of buttons
287 mContextualButtonGroup = new ContextualButtonGroup(R.id.menu_container);
Matthew Ng25593cc2018-09-12 16:05:41 -0700288 final ContextualButton imeSwitcherButton = new ContextualButton(R.id.ime_switcher,
289 R.drawable.ic_ime_switcher_default);
290 final RotationContextButton rotateSuggestionButton = new RotationContextButton(
Tracy Zhou24fd0282019-05-20 14:40:38 -0700291 R.id.rotate_suggestion, R.drawable.ic_sysbar_rotate_button);
Matthew Ng25593cc2018-09-12 16:05:41 -0700292 final ContextualButton accessibilityButton =
293 new ContextualButton(R.id.accessibility_button,
294 R.drawable.ic_sysbar_accessibility_button);
Matthew Ng25593cc2018-09-12 16:05:41 -0700295 mContextualButtonGroup.addButton(imeSwitcherButton);
Tracy Zhouefc34662019-04-22 13:37:12 -0700296 if (!isGesturalMode) {
297 mContextualButtonGroup.addButton(rotateSuggestionButton);
298 }
Matthew Ng25593cc2018-09-12 16:05:41 -0700299 mContextualButtonGroup.addButton(accessibilityButton);
300
Matthew Ngf2946542018-02-12 14:13:18 -0800301 mOverviewProxyService = Dependency.get(OverviewProxyService.class);
302 mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
Tracy Zhou24fd0282019-05-20 14:40:38 -0700303 mFloatingRotationButton = new FloatingRotationButton(context);
304 mRotationButtonController = new RotationButtonController(context,
305 R.style.RotateButtonCCWStart90,
306 isGesturalMode ? mFloatingRotationButton : rotateSuggestionButton);
Matthew Ngf2946542018-02-12 14:13:18 -0800307
Winsonfde2e6a2016-03-22 16:03:10 -0700308 mConfiguration = new Configuration();
Matthew Ng8c056c12018-10-15 15:16:46 -0700309 mTmpLastConfiguration = new Configuration();
Winsonfde2e6a2016-03-22 16:03:10 -0700310 mConfiguration.updateFrom(context.getResources().getConfiguration());
John Spurlocke932e302013-08-12 10:16:29 -0400311
Matthew Ng20136e62018-05-30 12:20:31 -0700312 mScreenPinningNotify = new ScreenPinningNotify(mContext);
Dave Mankoffbcaca8a2019-10-31 18:04:08 -0400313 mBarTransitions = new NavigationBarTransitions(this, Dependency.get(CommandQueue.class));
Jason Monka2081822016-01-18 14:41:03 -0500314
Sunny Goyal38412952020-04-17 11:35:37 -0700315 mButtonDispatchers.put(R.id.back, new ButtonDispatcher(R.id.back));
Felipe Leme15f915c2016-10-31 12:47:15 -0700316 mButtonDispatchers.put(R.id.home, new ButtonDispatcher(R.id.home));
Matthew Ngb55c02c2019-02-15 16:20:31 -0800317 mButtonDispatchers.put(R.id.home_handle, new ButtonDispatcher(R.id.home_handle));
Felipe Leme15f915c2016-10-31 12:47:15 -0700318 mButtonDispatchers.put(R.id.recent_apps, new ButtonDispatcher(R.id.recent_apps));
Matthew Ng25593cc2018-09-12 16:05:41 -0700319 mButtonDispatchers.put(R.id.ime_switcher, imeSwitcherButton);
320 mButtonDispatchers.put(R.id.accessibility_button, accessibilityButton);
321 mButtonDispatchers.put(R.id.rotate_suggestion, rotateSuggestionButton);
322 mButtonDispatchers.put(R.id.menu_container, mContextualButtonGroup);
Matthew Ng603b3292018-03-30 17:15:39 -0700323 mDeadZone = new DeadZone(this);
Matthew Ng86a436e2018-10-26 16:00:53 -0700324
Vinit Nayak59b114e62019-08-12 11:50:00 -0700325 mNavColorSampleMargin = getResources()
Vinit Nayak3f35db52019-08-08 17:31:48 -0700326 .getDimensionPixelSize(R.dimen.navigation_handle_sample_horizontal_margin);
Andy Wickham20297012019-11-06 14:56:26 -0800327 mEdgeBackGestureHandler = new EdgeBackGestureHandler(
328 context, mOverviewProxyService, mSysUiFlagContainer, mPluginManager);
Vinit Nayak3f35db52019-08-08 17:31:48 -0700329 mRegionSamplingHelper = new RegionSamplingHelper(this,
330 new RegionSamplingHelper.SamplingCallback() {
331 @Override
332 public void onRegionDarknessChanged(boolean isRegionDark) {
333 getLightTransitionsController().setIconsDark(!isRegionDark ,
334 true /* animate */);
335 }
336
337 @Override
338 public Rect getSampledRegion(View sampledView) {
Vinit Nayakd2fe92f2020-06-04 13:12:02 -0700339 if (mOrientedHandleSamplingRegion != null) {
340 return mOrientedHandleSamplingRegion;
341 }
342
Vinit Nayak3f35db52019-08-08 17:31:48 -0700343 updateSamplingRect();
344 return mSamplingBounds;
345 }
346
347 @Override
348 public boolean isSamplingEnabled() {
349 return isGesturalModeOnDefaultDisplay(getContext(), mNavBarMode);
350 }
351 });
John Spurlocke932e302013-08-12 10:16:29 -0400352 }
353
James O'Leary4335c702019-05-29 12:38:51 -0400354 public NavigationBarTransitions getBarTransitions() {
John Spurlocke932e302013-08-12 10:16:29 -0400355 return mBarTransitions;
356 }
357
Jorim Jaggi40db0292016-06-27 17:58:03 -0700358 public LightBarTransitionsController getLightTransitionsController() {
359 return mBarTransitions.getLightTransitionsController();
360 }
361
Dave Mankoffaf8163f2020-01-08 14:24:35 -0500362 public void setComponents(NotificationPanelViewController panel) {
Matthew Ng78f88d12018-01-23 12:39:55 -0800363 mPanelView = panel;
Winson Chung56a667b2019-07-30 13:51:27 -0700364 updatePanelSystemUiStateFlags();
Matthew Ng1cf6eac2018-11-27 15:06:55 -0800365 }
366
Jorim Jaggif4797922014-08-04 22:49:41 +0200367 public void setOnVerticalChangedListener(OnVerticalChangedListener onVerticalChangedListener) {
368 mOnVerticalChangedListener = onVerticalChangedListener;
Charles Chenaa94d95b2019-02-19 14:18:19 +0800369 notifyVerticalChangedListener(mIsVertical);
Jorim Jaggif4797922014-08-04 22:49:41 +0200370 }
371
Jim Millere898ac52012-04-06 17:10:57 -0700372 @Override
373 public boolean onInterceptTouchEvent(MotionEvent event) {
Sunny Goyala6a58122019-04-02 10:20:29 -0700374 return shouldDeadZoneConsumeTouchEvents(event) || super.onInterceptTouchEvent(event);
Jim Millere898ac52012-04-06 17:10:57 -0700375 }
376
Winson Chung4faf38a2018-02-06 08:53:37 -0800377 @Override
378 public boolean onTouchEvent(MotionEvent event) {
Matthew Ng472d3e42018-06-14 15:16:55 -0700379 shouldDeadZoneConsumeTouchEvents(event);
Winson Chung49658842018-02-08 12:52:21 -0800380 return super.onTouchEvent(event);
Winson Chung4faf38a2018-02-06 08:53:37 -0800381 }
382
Jorim Jaggi956ca412019-01-07 14:49:14 +0100383 void onTransientStateChanged(boolean isTransient) {
384 mEdgeBackGestureHandler.onNavBarTransientStateChanged(isTransient);
Winson Chung3d6c0802019-10-04 10:37:12 -0700385 }
386
Winson Chung775d2872019-03-27 14:14:01 -0700387 void onBarTransition(int newMode) {
388 if (newMode == MODE_OPAQUE) {
389 // If the nav bar background is opaque, stop auto tinting since we know the icons are
390 // showing over a dark background
Vinit Nayak3f35db52019-08-08 17:31:48 -0700391 mRegionSamplingHelper.stop();
Winson Chung775d2872019-03-27 14:14:01 -0700392 getLightTransitionsController().setIconsDark(false /* dark */, true /* animate */);
393 } else {
Vinit Nayak3f35db52019-08-08 17:31:48 -0700394 mRegionSamplingHelper.start(mSamplingBounds);
Winson Chung775d2872019-03-27 14:14:01 -0700395 }
396 }
397
Matthew Ng1e14e962018-05-03 12:51:43 -0700398 private boolean shouldDeadZoneConsumeTouchEvents(MotionEvent event) {
Sunny Goyala6a58122019-04-02 10:20:29 -0700399 int action = event.getActionMasked();
400 if (action == MotionEvent.ACTION_DOWN) {
401 mDeadZoneConsuming = false;
402 }
Matthew Ng1e14e962018-05-03 12:51:43 -0700403 if (mDeadZone.onTouchEvent(event) || mDeadZoneConsuming) {
Sunny Goyala6a58122019-04-02 10:20:29 -0700404 switch (action) {
Matthew Ng1e14e962018-05-03 12:51:43 -0700405 case MotionEvent.ACTION_DOWN:
406 // Allow gestures starting in the deadzone to be slippery
407 setSlippery(true);
408 mDeadZoneConsuming = true;
409 break;
410 case MotionEvent.ACTION_CANCEL:
411 case MotionEvent.ACTION_UP:
412 // When a gesture started in the deadzone is finished, restore slippery state
413 updateSlippery();
414 mDeadZoneConsuming = false;
415 break;
416 }
417 return true;
418 }
419 return false;
420 }
421
Xiyuan Xiaee7dd052015-05-15 09:46:27 -0700422 public void abortCurrentGesture() {
Jason Monka2081822016-01-18 14:41:03 -0500423 getHomeButton().abortCurrentGesture();
Xiyuan Xiaee7dd052015-05-15 09:46:27 -0700424 }
425
John Spurlock7edfbca2013-09-14 11:58:55 -0400426 public View getCurrentView() {
427 return mCurrentView;
428 }
429
Tracy Zhou24fd0282019-05-20 14:40:38 -0700430 public RotationButtonController getRotationButtonController() {
431 return mRotationButtonController;
432 }
433
434 public FloatingRotationButton getFloatingRotationButton() {
435 return mFloatingRotationButton;
436 }
437
Jason Monka2081822016-01-18 14:41:03 -0500438 public ButtonDispatcher getRecentsButton() {
Felipe Leme15f915c2016-10-31 12:47:15 -0700439 return mButtonDispatchers.get(R.id.recent_apps);
Daniel Sandler5c8da942011-06-28 00:29:04 -0400440 }
441
Jason Monka2081822016-01-18 14:41:03 -0500442 public ButtonDispatcher getBackButton() {
Felipe Leme15f915c2016-10-31 12:47:15 -0700443 return mButtonDispatchers.get(R.id.back);
Mike Lockwoode3646dd2011-09-01 12:46:28 -0400444 }
445
Jason Monka2081822016-01-18 14:41:03 -0500446 public ButtonDispatcher getHomeButton() {
Felipe Leme15f915c2016-10-31 12:47:15 -0700447 return mButtonDispatchers.get(R.id.home);
Mike Lockwoode3646dd2011-09-01 12:46:28 -0400448 }
449
Jason Monka2081822016-01-18 14:41:03 -0500450 public ButtonDispatcher getImeSwitchButton() {
Felipe Leme15f915c2016-10-31 12:47:15 -0700451 return mButtonDispatchers.get(R.id.ime_switcher);
Jason Monkf1ff2092014-04-29 16:50:53 -0400452 }
453
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800454 public ButtonDispatcher getAccessibilityButton() {
455 return mButtonDispatchers.get(R.id.accessibility_button);
456 }
457
Matthew Ng761562d2018-09-17 11:13:21 -0700458 public RotationContextButton getRotateSuggestionButton() {
Tracy Zhouefc34662019-04-22 13:37:12 -0700459 return (RotationContextButton) mButtonDispatchers.get(R.id.rotate_suggestion);
460 }
461
Matthew Ngb55c02c2019-02-15 16:20:31 -0800462 public ButtonDispatcher getHomeHandle() {
463 return mButtonDispatchers.get(R.id.home_handle);
464 }
465
Jorim Jaggi40db0292016-06-27 17:58:03 -0700466 public SparseArray<ButtonDispatcher> getButtonDispatchers() {
467 return mButtonDispatchers;
468 }
469
Matthew Ng9c3bce52018-02-01 22:00:31 +0000470 public boolean isRecentsButtonVisible() {
471 return getRecentsButton().getVisibility() == View.VISIBLE;
472 }
473
Matthew Ng6ff33b72018-02-27 13:47:38 -0800474 public boolean isOverviewEnabled() {
475 return (mDisabledFlags & View.STATUS_BAR_DISABLE_RECENT) == 0;
476 }
477
Matthew Ng8f25fb962018-01-16 17:17:24 -0800478 public boolean isQuickStepSwipeUpEnabled() {
Matthew Ngc1a97b12018-03-28 14:02:00 -0700479 return mOverviewProxyService.shouldShowSwipeUpUI() && isOverviewEnabled();
Matthew Ng8f25fb962018-01-16 17:17:24 -0800480 }
481
Matthew Ngd0a73e72018-03-02 15:16:03 -0800482 private void reloadNavIcons() {
Matthew Ng8c056c12018-10-15 15:16:46 -0700483 updateIcons(Configuration.EMPTY);
Matthew Ngd0a73e72018-03-02 15:16:03 -0800484 }
485
Matthew Ng8c056c12018-10-15 15:16:46 -0700486 private void updateIcons(Configuration oldConfig) {
487 final boolean orientationChange = oldConfig.orientation != mConfiguration.orientation;
488 final boolean densityChange = oldConfig.densityDpi != mConfiguration.densityDpi;
489 final boolean dirChange = oldConfig.getLayoutDirection() != mConfiguration.getLayoutDirection();
Matthew Ngca4592b2018-08-06 14:12:37 -0700490
491 if (orientationChange || densityChange) {
Matthew Ngd6865ba2018-08-27 17:58:41 -0700492 mDockedIcon = getDrawable(R.drawable.ic_sysbar_docked);
493 mHomeDefaultIcon = getHomeDrawable();
Winsonfde2e6a2016-03-22 16:03:10 -0700494 }
Matthew Ngca4592b2018-08-06 14:12:37 -0700495 if (densityChange || dirChange) {
Matthew Ngd6865ba2018-08-27 17:58:41 -0700496 mRecentIcon = getDrawable(R.drawable.ic_sysbar_recent);
Matthew Ng25593cc2018-09-12 16:05:41 -0700497 mContextualButtonGroup.updateIcons();
Winsonfde2e6a2016-03-22 16:03:10 -0700498 }
Matthew Ngca4592b2018-08-06 14:12:37 -0700499 if (orientationChange || densityChange || dirChange) {
Matthew Ngd6865ba2018-08-27 17:58:41 -0700500 mBackIcon = getBackDrawable();
Matthew Ngca4592b2018-08-06 14:12:37 -0700501 }
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700502 }
503
Matthew Ngd6865ba2018-08-27 17:58:41 -0700504 public KeyButtonDrawable getBackDrawable() {
Tracy Zhouefc34662019-04-22 13:37:12 -0700505 KeyButtonDrawable drawable = getDrawable(getBackDrawableRes());
Matthew Ngeb5ce832018-05-15 17:50:37 -0700506 orientBackButton(drawable);
507 return drawable;
Matthew Ng87cbf342018-02-15 12:21:18 -0800508 }
509
Tracy Zhouefc34662019-04-22 13:37:12 -0700510 public @DrawableRes int getBackDrawableRes() {
511 return chooseNavigationIconDrawableRes(R.drawable.ic_sysbar_back,
512 R.drawable.ic_sysbar_back_quick_step);
513 }
514
Matthew Ngd6865ba2018-08-27 17:58:41 -0700515 public KeyButtonDrawable getHomeDrawable() {
Matthew Ngeb5ce832018-05-15 17:50:37 -0700516 final boolean quickStepEnabled = mOverviewProxyService.shouldShowSwipeUpUI();
517 KeyButtonDrawable drawable = quickStepEnabled
Matthew Ngd6865ba2018-08-27 17:58:41 -0700518 ? getDrawable(R.drawable.ic_sysbar_home_quick_step)
519 : getDrawable(R.drawable.ic_sysbar_home);
Matthew Ngeb5ce832018-05-15 17:50:37 -0700520 orientHomeButton(drawable);
521 return drawable;
Matthew Ng87cbf342018-02-15 12:21:18 -0800522 }
523
Matthew Ngeb5ce832018-05-15 17:50:37 -0700524 private void orientBackButton(KeyButtonDrawable drawable) {
525 final boolean useAltBack =
Matthew Ngca4592b2018-08-06 14:12:37 -0700526 (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
Matthew Ng8c056c12018-10-15 15:16:46 -0700527 final boolean isRtl = mConfiguration.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
Matthew Ngd04bd0f2019-04-08 17:29:45 -0700528 float degrees = useAltBack ? (isRtl ? 90 : -90) : 0;
Matthew Ngca4592b2018-08-06 14:12:37 -0700529 if (drawable.getRotation() == degrees) {
530 return;
531 }
532
Tracy Zhou24fd0282019-05-20 14:40:38 -0700533 if (isGesturalMode(mNavBarMode)) {
Matthew Ngf03c3a62019-04-03 13:52:57 -0700534 drawable.setRotation(degrees);
535 return;
536 }
537
Matthew Ngca4592b2018-08-06 14:12:37 -0700538 // Animate the back button's rotation to the new degrees and only in portrait move up the
539 // back button to line up with the other buttons
Charles Chenaa94d95b2019-02-19 14:18:19 +0800540 float targetY = !mOverviewProxyService.shouldShowSwipeUpUI() && !mIsVertical && useAltBack
Matthew Ngca4592b2018-08-06 14:12:37 -0700541 ? - getResources().getDimension(R.dimen.navbar_back_button_ime_offset)
542 : 0;
543 ObjectAnimator navBarAnimator = ObjectAnimator.ofPropertyValuesHolder(drawable,
544 PropertyValuesHolder.ofFloat(KeyButtonDrawable.KEY_DRAWABLE_ROTATE, degrees),
545 PropertyValuesHolder.ofFloat(KeyButtonDrawable.KEY_DRAWABLE_TRANSLATE_Y, targetY));
546 navBarAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
547 navBarAnimator.setDuration(200);
548 navBarAnimator.start();
Matthew Ng87cbf342018-02-15 12:21:18 -0800549 }
550
Matthew Ngeb5ce832018-05-15 17:50:37 -0700551 private void orientHomeButton(KeyButtonDrawable drawable) {
Charles Chenaa94d95b2019-02-19 14:18:19 +0800552 drawable.setRotation(mIsVertical ? 90 : 0);
Matthew Ngeb5ce832018-05-15 17:50:37 -0700553 }
554
Matthew Ngd6865ba2018-08-27 17:58:41 -0700555 private KeyButtonDrawable chooseNavigationIconDrawable(@DrawableRes int icon,
556 @DrawableRes int quickStepIcon) {
Tracy Zhouefc34662019-04-22 13:37:12 -0700557 return getDrawable(chooseNavigationIconDrawableRes(icon, quickStepIcon));
558 }
559
560 private @DrawableRes int chooseNavigationIconDrawableRes(@DrawableRes int icon,
561 @DrawableRes int quickStepIcon) {
Matthew Ngc1a97b12018-03-28 14:02:00 -0700562 final boolean quickStepEnabled = mOverviewProxyService.shouldShowSwipeUpUI();
Tracy Zhouefc34662019-04-22 13:37:12 -0700563 return quickStepEnabled ? quickStepIcon : icon;
Matthew Ngeb5ce832018-05-15 17:50:37 -0700564 }
565
Matthew Ngd6865ba2018-08-27 17:58:41 -0700566 private KeyButtonDrawable getDrawable(@DrawableRes int icon) {
Matthew Ng25593cc2018-09-12 16:05:41 -0700567 return KeyButtonDrawable.create(mContext, icon, true /* hasShadow */);
Matthew Ngeb5ce832018-05-15 17:50:37 -0700568 }
569
Matthew Ngd6865ba2018-08-27 17:58:41 -0700570 private KeyButtonDrawable getDrawable(@DrawableRes int icon, boolean hasShadow) {
Matthew Ng25593cc2018-09-12 16:05:41 -0700571 return KeyButtonDrawable.create(mContext, icon, hasShadow);
Mike Digman7d092772018-01-11 12:10:32 -0800572 }
573
Vinit Nayak3f35db52019-08-08 17:31:48 -0700574 /** To be called when screen lock/unlock state changes */
575 public void onScreenStateChanged(boolean isScreenOn) {
576 if (isScreenOn) {
577 if (isGesturalModeOnDefaultDisplay(getContext(), mNavBarMode)) {
578 mRegionSamplingHelper.start(mSamplingBounds);
579 }
580 } else {
581 mRegionSamplingHelper.stop();
582 }
583 }
584
Winson Chung2102ae82019-06-19 13:15:24 -0700585 public void setWindowVisible(boolean visible) {
Vinit Nayak3f35db52019-08-08 17:31:48 -0700586 mRegionSamplingHelper.setWindowVisible(visible);
Winson Chung2102ae82019-06-19 13:15:24 -0700587 mRotationButtonController.onNavigationBarWindowVisibilityChange(visible);
588 }
589
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700590 @Override
591 public void setLayoutDirection(int layoutDirection) {
Matthew Ngd0a73e72018-03-02 15:16:03 -0800592 reloadNavIcons();
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700593
594 super.setLayoutDirection(layoutDirection);
Daniel Sandler1d4d30a2011-04-28 12:35:29 -0400595 }
596
Matthew Ngd0a73e72018-03-02 15:16:03 -0800597 public void setNavigationIconHints(int hints) {
598 if (hints == mNavigationIconHints) return;
Matthew Ng691d5582019-04-04 14:59:17 -0700599 final boolean newBackAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
600 final boolean oldBackAlt =
601 (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
602 if (newBackAlt != oldBackAlt) {
603 onImeVisibilityChanged(newBackAlt);
John Spurlock56d007b2013-10-28 18:40:56 -0400604 }
Matthew Ng691d5582019-04-04 14:59:17 -0700605
Daniel Sandler328310c2011-09-23 15:56:52 -0400606 if (DEBUG) {
John Spurlock01534782014-01-13 11:59:22 -0500607 android.widget.Toast.makeText(getContext(),
Daniel Sandler328310c2011-09-23 15:56:52 -0400608 "Navigation icon hints = " + hints,
609 500).show();
610 }
Daniel Sandler328310c2011-09-23 15:56:52 -0400611 mNavigationIconHints = hints;
Matthew Ngd0a73e72018-03-02 15:16:03 -0800612 updateNavButtonIcons();
613 }
Daniel Sandler328310c2011-09-23 15:56:52 -0400614
Matthew Ng691d5582019-04-04 14:59:17 -0700615 private void onImeVisibilityChanged(boolean visible) {
616 if (!visible) {
617 mTransitionListener.onBackAltCleared();
618 }
619 mImeVisible = visible;
Tracy Zhou24fd0282019-05-20 14:40:38 -0700620 mRotationButtonController.getRotationButton().setCanShowRotationButton(!mImeVisible);
Matthew Ng691d5582019-04-04 14:59:17 -0700621 }
622
Matthew Ngd0a73e72018-03-02 15:16:03 -0800623 public void setDisabledFlags(int disabledFlags) {
624 if (mDisabledFlags == disabledFlags) return;
625
626 final boolean overviewEnabledBefore = isOverviewEnabled();
627 mDisabledFlags = disabledFlags;
628
629 // Update icons if overview was just enabled to ensure the correct icons are present
630 if (!overviewEnabledBefore && isOverviewEnabled()) {
631 reloadNavIcons();
632 }
633
634 updateNavButtonIcons();
Winson Chung1be4c7e2018-05-23 18:24:13 -0700635 updateSlippery();
Tracy Zhou98140912018-06-05 12:09:14 -0700636 setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
Winson Chung56a667b2019-07-30 13:51:27 -0700637 updateDisabledSystemUiStateFlags();
Matthew Ngd0a73e72018-03-02 15:16:03 -0800638 }
639
640 public void updateNavButtonIcons() {
Sriram Viswanathan9ebbe6a2015-11-16 17:59:22 -0800641 // We have to replace or restore the back and home button icons when exiting or entering
642 // carmode, respectively. Recents are not available in CarMode in nav bar so change
643 // to recent icon is not required.
Matthew Ngeb5ce832018-05-15 17:50:37 -0700644 final boolean useAltBack =
645 (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
Matthew Ngd6865ba2018-08-27 17:58:41 -0700646 KeyButtonDrawable backIcon = mBackIcon;
Matthew Ngec5b8412018-08-22 10:45:08 -0700647 orientBackButton(backIcon);
Matthew Ngd6865ba2018-08-27 17:58:41 -0700648 KeyButtonDrawable homeIcon = mHomeDefaultIcon;
Matthew Ngeb5ce832018-05-15 17:50:37 -0700649 if (!mUseCarModeUi) {
Matthew Ngeb5ce832018-05-15 17:50:37 -0700650 orientHomeButton(homeIcon);
651 }
652 getHomeButton().setImageDrawable(homeIcon);
Jason Monka2081822016-01-18 14:41:03 -0500653 getBackButton().setImageDrawable(backIcon);
Sriram Viswanathan9ebbe6a2015-11-16 17:59:22 -0800654
Jorim Jaggid30d95d2016-02-17 20:27:22 -0800655 updateRecentsIcon();
Sriram Viswanathan9ebbe6a2015-11-16 17:59:22 -0800656
Mike Digmana48cf192018-02-12 17:52:48 -0800657 // Update IME button visibility, a11y and rotate button always overrides the appearance
Tracy Zhouefc34662019-04-22 13:37:12 -0700658 mContextualButtonGroup.setButtonVisibility(R.id.ime_switcher,
Matthew Ng25593cc2018-09-12 16:05:41 -0700659 (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800660
Jorim Jaggi40db0292016-06-27 17:58:03 -0700661 mBarTransitions.reapplyDarkIntensity();
Daniel Sandler328310c2011-09-23 15:56:52 -0400662
Tracy Zhou24fd0282019-05-20 14:40:38 -0700663 boolean disableHome = isGesturalMode(mNavBarMode)
Winson Chunge108b672019-03-06 16:11:28 -0800664 || ((mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
Sriram Viswanathan469caae2016-03-22 13:11:50 -0700665
Jeff Chang2aaa91a2018-11-08 18:04:16 +0800666 // Always disable recents when alternate car mode UI is active and for secondary displays.
667 boolean disableRecent = isRecentsButtonDisabled();
Charles Hee57ff812017-10-26 10:01:35 +0100668
Sunny Goyalbe4e0542019-08-08 16:36:14 -0700669 // Disable the home handle if both hone and recents are disabled
670 boolean disableHomeHandle = disableRecent
671 && ((mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
672
Sunny Goyal38412952020-04-17 11:35:37 -0700673 boolean disableBack = !useAltBack && (mEdgeBackGestureHandler.isHandlingGestures()
Matthew Ngf03c3a62019-04-03 13:52:57 -0700674 || ((mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0));
Daniel Sandler029d5872011-09-12 00:58:58 -0400675
Matthew Ng87cbf342018-02-15 12:21:18 -0800676 // When screen pinning, don't hide back and home when connected service or back and
677 // recents buttons when disconnected from launcher service in screen pinning mode,
678 // as they are used for exiting.
Matthew Ng6ff33b72018-02-27 13:47:38 -0800679 final boolean pinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive();
Winson Chungd95a2252018-04-04 17:02:29 +0000680 if (mOverviewProxyService.isEnabled()) {
Winson Chung30c62602019-05-09 13:34:48 -0700681 // Force disable recents when not in legacy mode
682 disableRecent |= !QuickStepContract.isLegacyMode(mNavBarMode);
Tracy Zhou63b50472019-07-01 15:27:02 -0700683 if (pinningActive && !QuickStepContract.isGesturalMode(mNavBarMode)) {
Matthew Ng87cbf342018-02-15 12:21:18 -0800684 disableBack = disableHome = false;
Matthew Ng87cbf342018-02-15 12:21:18 -0800685 }
Matthew Ng6ff33b72018-02-27 13:47:38 -0800686 } else if (pinningActive) {
Matthew Ng87cbf342018-02-15 12:21:18 -0800687 disableBack = disableRecent = false;
Matthew Ngdc79e5c2017-12-14 17:37:35 -0800688 }
Charles Hee57ff812017-10-26 10:01:35 +0100689
Winson Chunge108b672019-03-06 16:11:28 -0800690 ViewGroup navButtons = getCurrentView().findViewById(R.id.nav_buttons);
John Spurlock56d007b2013-10-28 18:40:56 -0400691 if (navButtons != null) {
692 LayoutTransition lt = navButtons.getLayoutTransition();
John Spurlock1bbd49d2012-10-19 11:09:32 -0400693 if (lt != null) {
John Spurlock56d007b2013-10-28 18:40:56 -0400694 if (!lt.getTransitionListeners().contains(mTransitionListener)) {
695 lt.addTransitionListener(mTransitionListener);
696 }
John Spurlock1bbd49d2012-10-19 11:09:32 -0400697 }
698 }
699
Sunny Goyal38412952020-04-17 11:35:37 -0700700 getBackButton().setVisibility(disableBack ? View.INVISIBLE : View.VISIBLE);
701 getHomeButton().setVisibility(disableHome ? View.INVISIBLE : View.VISIBLE);
702 getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE);
Sunny Goyalbe4e0542019-08-08 16:36:14 -0700703 getHomeHandle().setVisibility(disableHomeHandle ? View.INVISIBLE : View.VISIBLE);
John Spurlock56d007b2013-10-28 18:40:56 -0400704 }
705
Jeff Chang2aaa91a2018-11-08 18:04:16 +0800706 @VisibleForTesting
707 boolean isRecentsButtonDisabled() {
708 return mUseCarModeUi || !isOverviewEnabled()
709 || getContext().getDisplayId() != Display.DEFAULT_DISPLAY;
710 }
711
712 private Display getContextDisplay() {
713 return getContext().getDisplay();
714 }
715
Jorim Jaggi37c11802015-08-18 20:27:54 -0700716 public void setLayoutTransitionsEnabled(boolean enabled) {
717 mLayoutTransitionsEnabled = enabled;
718 updateLayoutTransitionsEnabled();
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700719 }
720
Jorim Jaggi37c11802015-08-18 20:27:54 -0700721 public void setWakeAndUnlocking(boolean wakeAndUnlocking) {
722 setUseFadingAnimations(wakeAndUnlocking);
723 mWakeAndUnlocking = wakeAndUnlocking;
724 updateLayoutTransitionsEnabled();
725 }
726
727 private void updateLayoutTransitionsEnabled() {
728 boolean enabled = !mWakeAndUnlocking && mLayoutTransitionsEnabled;
Rakesh Iyer1186faa2015-12-07 16:48:46 -0800729 ViewGroup navButtons = (ViewGroup) getCurrentView().findViewById(R.id.nav_buttons);
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700730 LayoutTransition lt = navButtons.getLayoutTransition();
Julia Reynolds8478aba2015-07-31 09:17:20 -0400731 if (lt != null) {
732 if (enabled) {
733 lt.enableTransitionType(LayoutTransition.APPEARING);
734 lt.enableTransitionType(LayoutTransition.DISAPPEARING);
735 lt.enableTransitionType(LayoutTransition.CHANGE_APPEARING);
736 lt.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
737 } else {
738 lt.disableTransitionType(LayoutTransition.APPEARING);
739 lt.disableTransitionType(LayoutTransition.DISAPPEARING);
740 lt.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
741 lt.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
742 }
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700743 }
744 }
745
746 private void setUseFadingAnimations(boolean useFadingAnimations) {
Jason Monk49fa0162017-01-11 09:21:56 -0500747 WindowManager.LayoutParams lp = (WindowManager.LayoutParams) ((ViewGroup) getParent())
748 .getLayoutParams();
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700749 if (lp != null) {
750 boolean old = lp.windowAnimations != 0;
751 if (!old && useFadingAnimations) {
752 lp.windowAnimations = R.style.Animation_NavigationBarFadeIn;
753 } else if (old && !useFadingAnimations) {
754 lp.windowAnimations = 0;
755 } else {
756 return;
757 }
758 WindowManager wm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
Jason Monk49fa0162017-01-11 09:21:56 -0500759 wm.updateViewLayout((View) getParent(), lp);
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700760 }
761 }
762
Winson Chung5b6a1fe2019-07-26 16:38:08 -0700763 public void onStatusBarPanelStateChanged() {
Matthew Ng78f88d12018-01-23 12:39:55 -0800764 updateSlippery();
Winson Chung56a667b2019-07-30 13:51:27 -0700765 updatePanelSystemUiStateFlags();
Winson Chunga7067002019-05-07 11:50:42 -0700766 }
767
Winson Chung56a667b2019-07-30 13:51:27 -0700768 public void updateDisabledSystemUiStateFlags() {
Winson Chunga7067002019-05-07 11:50:42 -0700769 int displayId = mContext.getDisplayId();
Vinit Nayak59b114e62019-08-12 11:50:00 -0700770
771 mSysUiFlagContainer.setFlag(SYSUI_STATE_SCREEN_PINNING,
772 ActivityManagerWrapper.getInstance().isScreenPinningActive())
773 .setFlag(SYSUI_STATE_OVERVIEW_DISABLED,
774 (mDisabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0)
775 .setFlag(SYSUI_STATE_HOME_DISABLED,
776 (mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0)
777 .setFlag(SYSUI_STATE_SEARCH_DISABLED,
778 (mDisabledFlags & View.STATUS_BAR_DISABLE_SEARCH) != 0)
779 .commitUpdate(displayId);
Winson Chung56a667b2019-07-30 13:51:27 -0700780 }
781
782 public void updatePanelSystemUiStateFlags() {
783 int displayId = mContext.getDisplayId();
Winson Chung75375e02020-02-12 15:43:48 -0800784 if (SysUiState.DEBUG) {
785 Log.d(TAG, "Updating panel sysui state flags: panelView=" + mPanelView);
786 }
Winson Chunga7067002019-05-07 11:50:42 -0700787 if (mPanelView != null) {
Winson Chung75375e02020-02-12 15:43:48 -0800788 if (SysUiState.DEBUG) {
789 Log.d(TAG, "Updating panel sysui state flags: fullyExpanded="
790 + mPanelView.isFullyExpanded() + " inQs=" + mPanelView.isInSettings());
791 }
Vinit Nayak59b114e62019-08-12 11:50:00 -0700792 mSysUiFlagContainer.setFlag(SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
793 mPanelView.isFullyExpanded() && !mPanelView.isInSettings())
794 .setFlag(SYSUI_STATE_QUICK_SETTINGS_EXPANDED,
795 mPanelView.isInSettings())
796 .commitUpdate(displayId);
Winson Chunga7067002019-05-07 11:50:42 -0700797 }
Matthew Ng78f88d12018-01-23 12:39:55 -0800798 }
799
Matthew Ng8f25fb962018-01-16 17:17:24 -0800800 public void updateStates() {
Matthew Ng44b14502018-05-04 11:10:14 -0700801 final boolean showSwipeUpUI = mOverviewProxyService.shouldShowSwipeUpUI();
Mike Digmanf77fb912018-05-21 11:21:30 -0700802
803 if (mNavigationInflaterView != null) {
804 // Reinflate the navbar if needed, no-op unless the swipe up state changes
805 mNavigationInflaterView.onLikelyDefaultLayoutChange();
806 }
807
Matthew Ng8f25fb962018-01-16 17:17:24 -0800808 updateSlippery();
Winson Chung770d7e92018-03-20 17:51:39 -0700809 reloadNavIcons();
Matthew Ngd0a73e72018-03-02 15:16:03 -0800810 updateNavButtonIcons();
Winson Chungf9e30272018-03-26 17:25:36 -0700811 setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
Matthew Ng44b14502018-05-04 11:10:14 -0700812 WindowManagerWrapper.getInstance().setNavBarVirtualKeyHapticFeedbackEnabled(!showSwipeUpUI);
813 getHomeButton().setAccessibilityDelegate(
814 showSwipeUpUI ? mQuickStepAccessibilityDelegate : null);
Matthew Ng8f25fb962018-01-16 17:17:24 -0800815 }
816
Matthew Ng90ef0632018-08-15 13:53:15 -0700817 /**
818 * Updates the {@link WindowManager.LayoutParams.FLAG_SLIPPERY} state dependent on if swipe up
819 * is enabled, or the notifications is fully opened without being in an animated state. If
820 * slippery is enabled, touch events will leave the nav bar window and enter into the fullscreen
821 * app/home window, if not nav bar will receive a cancelled touch event once gesture leaves bar.
822 */
Matthew Ng472d3e42018-06-14 15:16:55 -0700823 public void updateSlippery() {
Matthew Ng90ef0632018-08-15 13:53:15 -0700824 setSlippery(!isQuickStepSwipeUpEnabled() ||
Dave Mankoff023e5da2020-06-17 11:35:01 -0400825 (mPanelView != null && mPanelView.isFullyExpanded() && !mPanelView.isCollapsing()));
Matthew Ng78f88d12018-01-23 12:39:55 -0800826 }
827
Matthew Ng7d05e772017-11-09 14:41:07 -0800828 private void setSlippery(boolean slippery) {
Matthew Ngb831fb42019-01-30 11:20:48 -0800829 setWindowFlag(WindowManager.LayoutParams.FLAG_SLIPPERY, slippery);
830 }
831
Matthew Ngb831fb42019-01-30 11:20:48 -0800832 private void setWindowFlag(int flags, boolean enable) {
Matthew Ng7d05e772017-11-09 14:41:07 -0800833 final ViewGroup navbarView = ((ViewGroup) getParent());
Matthew Ngb55c02c2019-02-15 16:20:31 -0800834 if (navbarView == null) {
835 return;
836 }
Matthew Ngb831fb42019-01-30 11:20:48 -0800837 WindowManager.LayoutParams lp = (WindowManager.LayoutParams) navbarView.getLayoutParams();
838 if (lp == null || enable == ((lp.flags & flags) != 0)) {
Matthew Ng9c3bce52018-02-01 22:00:31 +0000839 return;
840 }
Matthew Ngb831fb42019-01-30 11:20:48 -0800841 if (enable) {
842 lp.flags |= flags;
843 } else {
844 lp.flags &= ~flags;
Matthew Ng7d05e772017-11-09 14:41:07 -0800845 }
Matthew Ngb831fb42019-01-30 11:20:48 -0800846 WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
847 wm.updateViewLayout(navbarView, lp);
Matthew Ng7d05e772017-11-09 14:41:07 -0800848 }
849
Winson Chung1aa24b92019-04-24 15:17:33 -0700850 @Override
851 public void onNavigationModeChanged(int mode) {
852 mNavBarMode = mode;
853 mBarTransitions.onNavigationModeChanged(mNavBarMode);
Sunny Goyal38412952020-04-17 11:35:37 -0700854 mEdgeBackGestureHandler.onNavigationModeChanged(mNavBarMode);
Winson Chung1aa24b92019-04-24 15:17:33 -0700855 mRecentsOnboarding.onNavigationModeChanged(mNavBarMode);
Tracy Zhouefc34662019-04-22 13:37:12 -0700856 getRotateSuggestionButton().onNavigationModeChanged(mNavBarMode);
Matthew Ngb55c02c2019-02-15 16:20:31 -0800857
Winson Chungefaacc32019-09-25 14:44:05 -0700858 if (isGesturalMode(mNavBarMode)) {
859 mRegionSamplingHelper.start(mSamplingBounds);
860 } else {
861 mRegionSamplingHelper.stop();
862 }
Matthew Ngb55c02c2019-02-15 16:20:31 -0800863 }
864
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800865 public void setAccessibilityButtonState(final boolean visible, final boolean longClickable) {
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800866 mLongClickableAccessibilityButton = longClickable;
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800867 getAccessibilityButton().setLongClickable(longClickable);
Tracy Zhouefc34662019-04-22 13:37:12 -0700868 mContextualButtonGroup.setButtonVisibility(R.id.accessibility_button, visible);
Mike Digmana48cf192018-02-12 17:52:48 -0800869 }
870
Tracy Zhou1ac592c2018-07-25 13:47:37 -0700871 void hideRecentsOnboarding() {
872 mRecentsOnboarding.hide(true);
873 }
874
Jim Miller960892c2012-05-23 15:50:04 -0700875 @Override
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400876 public void onFinishInflate() {
Sunny Goyal38412952020-04-17 11:35:37 -0700877 super.onFinishInflate();
Winson Chung661d5f92018-05-21 18:41:39 -0700878 mNavigationInflaterView = findViewById(R.id.navigation_inflater);
Felipe Leme15f915c2016-10-31 12:47:15 -0700879 mNavigationInflaterView.setButtonDispatchers(mButtonDispatchers);
Jason Monka2081822016-01-18 14:41:03 -0500880
881 getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
Selim Cinek17a327a2014-08-25 15:03:48 +0200882
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000883 Divider divider = Dependency.get(Divider.class);
884 divider.registerInSplitScreenListener(mDockedListener);
Charles Chenaa94d95b2019-02-19 14:18:19 +0800885 updateOrientationViews();
Matthew Ng25593cc2018-09-12 16:05:41 -0700886 reloadNavIcons();
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100887 }
888
Matthew Nga8f24262017-12-19 11:54:24 -0800889 @Override
890 protected void onDraw(Canvas canvas) {
Matthew Ng603b3292018-03-30 17:15:39 -0700891 mDeadZone.onDraw(canvas);
Matthew Nga8f24262017-12-19 11:54:24 -0800892 super.onDraw(canvas);
893 }
894
Vinit Nayak3f35db52019-08-08 17:31:48 -0700895 private void updateSamplingRect() {
896 mSamplingBounds.setEmpty();
897 // TODO: Extend this to 2/3 button layout as well
898 View view = getHomeHandle().getCurrentView();
899
900 if (view != null) {
901 int[] pos = new int[2];
902 view.getLocationOnScreen(pos);
903 Point displaySize = new Point();
904 view.getContext().getDisplay().getRealSize(displaySize);
905 final Rect samplingBounds = new Rect(pos[0] - mNavColorSampleMargin,
906 displaySize.y - getNavBarHeight(),
907 pos[0] + view.getWidth() + mNavColorSampleMargin,
908 displaySize.y);
909 mSamplingBounds.set(samplingBounds);
910 }
911 }
912
Vinit Nayakd2fe92f2020-06-04 13:12:02 -0700913 void setOrientedHandleSamplingRegion(Rect orientedHandleSamplingRegion) {
914 mOrientedHandleSamplingRegion = orientedHandleSamplingRegion;
915 mRegionSamplingHelper.updateSamplingRect();
916 }
917
Matthew Nga8f24262017-12-19 11:54:24 -0800918 @Override
919 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
920 super.onLayout(changed, left, top, right, bottom);
Sunny Goyalaac6c882019-02-11 11:57:58 -0800921
922 mActiveRegion.setEmpty();
923 updateButtonLocation(getBackButton(), mBackButtonBounds, true);
924 updateButtonLocation(getHomeButton(), mHomeButtonBounds, false);
925 updateButtonLocation(getRecentsButton(), mRecentsButtonBounds, false);
926 updateButtonLocation(getRotateSuggestionButton(), mRotationButtonBounds, true);
927 // TODO: Handle button visibility changes
928 mOverviewProxyService.onActiveNavBarRegionChanges(mActiveRegion);
Tracy Zhou559d97c2018-04-07 23:54:46 -0700929 mRecentsOnboarding.setNavBarHeight(getMeasuredHeight());
Matthew Nga8f24262017-12-19 11:54:24 -0800930 }
931
Sunny Goyalaac6c882019-02-11 11:57:58 -0800932 private void updateButtonLocation(ButtonDispatcher button, Rect buttonBounds,
933 boolean isActive) {
Winson Chungc4e06202018-02-13 10:37:35 -0800934 View view = button.getCurrentView();
935 if (view == null) {
936 buttonBounds.setEmpty();
937 return;
938 }
Matthew Ng3b7e3902018-03-22 16:06:09 -0700939 // Temporarily reset the translation back to origin to get the position in window
940 final float posX = view.getTranslationX();
941 final float posY = view.getTranslationY();
942 view.setTranslationX(0);
943 view.setTranslationY(0);
Sunny Goyalaac6c882019-02-11 11:57:58 -0800944
945 if (isActive) {
946 view.getLocationOnScreen(mTmpPosition);
947 buttonBounds.set(mTmpPosition[0], mTmpPosition[1],
948 mTmpPosition[0] + view.getMeasuredWidth(),
949 mTmpPosition[1] + view.getMeasuredHeight());
950 mActiveRegion.op(buttonBounds, Op.UNION);
951 }
Winson Chungc4e06202018-02-13 10:37:35 -0800952 view.getLocationInWindow(mTmpPosition);
953 buttonBounds.set(mTmpPosition[0], mTmpPosition[1],
954 mTmpPosition[0] + view.getMeasuredWidth(),
955 mTmpPosition[1] + view.getMeasuredHeight());
Matthew Ng3b7e3902018-03-22 16:06:09 -0700956 view.setTranslationX(posX);
957 view.setTranslationY(posY);
Winson Chungc4e06202018-02-13 10:37:35 -0800958 }
959
Charles Chenaa94d95b2019-02-19 14:18:19 +0800960 private void updateOrientationViews() {
961 mHorizontal = findViewById(R.id.horizontal);
962 mVertical = findViewById(R.id.vertical);
Jason Monk9a6552d2016-05-20 11:21:59 -0400963
Jason Monk199a2d02017-07-28 11:08:27 -0400964 updateCurrentView();
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400965 }
966
Charles Chenaa94d95b2019-02-19 14:18:19 +0800967 boolean needsReorient(int rotation) {
Adrian Roosa98b32c2016-08-11 10:41:08 -0700968 return mCurrentRotation != rotation;
Adrian Roos090b7d82016-08-02 18:36:12 -0700969 }
970
Jason Monk199a2d02017-07-28 11:08:27 -0400971 private void updateCurrentView() {
Charles Chenaa94d95b2019-02-19 14:18:19 +0800972 resetViews();
973 mCurrentView = mIsVertical ? mVertical : mHorizontal;
Daniel Sandler5c8da942011-06-28 00:29:04 -0400974 mCurrentView.setVisibility(View.VISIBLE);
Charles Chenaa94d95b2019-02-19 14:18:19 +0800975 mNavigationInflaterView.setVertical(mIsVertical);
976 mCurrentRotation = getContextDisplay().getRotation();
977 mNavigationInflaterView.setAlternativeOrder(mCurrentRotation == Surface.ROTATION_90);
Matthew Ng1efc9c32018-04-11 18:13:56 -0700978 mNavigationInflaterView.updateButtonDispatchersCurrentView();
Jorim Jaggi37c11802015-08-18 20:27:54 -0700979 updateLayoutTransitionsEnabled();
Charles Chenaa94d95b2019-02-19 14:18:19 +0800980 }
981
982 private void resetViews() {
983 mHorizontal.setVisibility(View.GONE);
984 mVertical.setVisibility(View.GONE);
Jason Monk9a6552d2016-05-20 11:21:59 -0400985 }
986
987 private void updateRecentsIcon() {
Charles Chenaa94d95b2019-02-19 14:18:19 +0800988 mDockedIcon.setRotation(mDockedStackExists && mIsVertical ? 90 : 0);
Jason Monk9a6552d2016-05-20 11:21:59 -0400989 getRecentsButton().setImageDrawable(mDockedStackExists ? mDockedIcon : mRecentIcon);
Jorim Jaggi40db0292016-06-27 17:58:03 -0700990 mBarTransitions.reapplyDarkIntensity();
Jason Monk9a6552d2016-05-20 11:21:59 -0400991 }
992
Matthew Ng20136e62018-05-30 12:20:31 -0700993 public void showPinningEnterExitToast(boolean entering) {
994 if (entering) {
995 mScreenPinningNotify.showPinningStartToast();
996 } else {
997 mScreenPinningNotify.showPinningExitToast();
998 }
999 }
1000
1001 public void showPinningEscapeToast() {
Hongwei Wang0e625742019-08-14 14:55:27 -07001002 mScreenPinningNotify.showEscapeToast(
1003 mNavBarMode == NAV_BAR_MODE_GESTURAL, isRecentsButtonVisible());
Matthew Ng20136e62018-05-30 12:20:31 -07001004 }
1005
Jason Monk9a6552d2016-05-20 11:21:59 -04001006 public boolean isVertical() {
Charles Chenaa94d95b2019-02-19 14:18:19 +08001007 return mIsVertical;
Jason Monk9a6552d2016-05-20 11:21:59 -04001008 }
1009
1010 public void reorient() {
Jason Monk199a2d02017-07-28 11:08:27 -04001011 updateCurrentView();
Daniel Sandler8956dbb2011-04-22 07:55:02 -04001012
Siarhei Vishniakoufdb42772017-06-29 10:32:11 -07001013 ((NavigationBarFrame) getRootView()).setDeadZone(mDeadZone);
Matthew Ng603b3292018-03-30 17:15:39 -07001014 mDeadZone.onConfigurationChanged(mCurrentRotation);
Daniel Sandlerc26185b2012-08-29 15:49:53 -04001015
Daniel Sandler6da2b762011-09-14 16:04:59 -04001016 // force the low profile & disabled states into compliance
Adrian Roos8a8ffd42015-05-26 18:30:37 -07001017 mBarTransitions.init();
Daniel Sandler6da2b762011-09-14 16:04:59 -04001018
Daniel Sandler60ee2562011-07-22 12:34:33 -04001019 if (DEBUG) {
Adrian Roosa98b32c2016-08-11 10:41:08 -07001020 Log.d(TAG, "reorient(): rot=" + mCurrentRotation);
Daniel Sandler60ee2562011-07-22 12:34:33 -04001021 }
Michael Jurkaa5d0ddb2012-03-09 17:41:41 -08001022
Matthew Ng5fd80412018-02-14 14:40:31 -08001023 // Resolve layout direction if not resolved since components changing layout direction such
1024 // as changing languages will recreate this view and the direction will be resolved later
1025 if (!isLayoutDirectionResolved()) {
1026 resolveLayoutDirection();
1027 }
Matthew Ngd0a73e72018-03-02 15:16:03 -08001028 updateNavButtonIcons();
Xiaohui Chen9efa5de2016-11-22 10:34:38 -08001029
Charles Chenaa94d95b2019-02-19 14:18:19 +08001030 getHomeButton().setVertical(mIsVertical);
Daniel Sandler8956dbb2011-04-22 07:55:02 -04001031 }
Daniel Sandler48852952011-12-01 14:34:23 -05001032
Daniel Sandler0b69b592012-01-23 21:08:36 -05001033 @Override
Matthew Ngff638122019-03-21 17:17:18 -07001034 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
1035 int w = MeasureSpec.getSize(widthMeasureSpec);
1036 int h = MeasureSpec.getSize(heightMeasureSpec);
John Spurlockcd686b52013-06-05 10:13:46 -04001037 if (DEBUG) Log.d(TAG, String.format(
Matthew Ngff638122019-03-21 17:17:18 -07001038 "onMeasure: (%dx%d) old: (%dx%d)", w, h, getMeasuredWidth(), getMeasuredHeight()));
Daniel Sandlere03bc952012-04-27 16:11:22 -04001039
Winson Chung4723b4e2019-03-25 16:49:36 -07001040 final boolean newVertical = w > 0 && h > w
Tracy Zhou24fd0282019-05-20 14:40:38 -07001041 && !isGesturalMode(mNavBarMode);
Charles Chenaa94d95b2019-02-19 14:18:19 +08001042 if (newVertical != mIsVertical) {
1043 mIsVertical = newVertical;
1044 if (DEBUG) {
Matthew Ngff638122019-03-21 17:17:18 -07001045 Log.d(TAG, String.format("onMeasure: h=%d, w=%d, vert=%s", h, w,
Charles Chenaa94d95b2019-02-19 14:18:19 +08001046 mIsVertical ? "y" : "n"));
1047 }
Daniel Sandlere03bc952012-04-27 16:11:22 -04001048 reorient();
Selim Cinek92d892c2014-09-11 15:11:00 +02001049 notifyVerticalChangedListener(newVertical);
Daniel Sandlere03bc952012-04-27 16:11:22 -04001050 }
Winson Chung775d2872019-03-27 14:14:01 -07001051
Tracy Zhou24fd0282019-05-20 14:40:38 -07001052 if (isGesturalMode(mNavBarMode)) {
Winson Chung775d2872019-03-27 14:14:01 -07001053 // Update the nav bar background to match the height of the visible nav bar
1054 int height = mIsVertical
1055 ? getResources().getDimensionPixelSize(
1056 com.android.internal.R.dimen.navigation_bar_height_landscape)
1057 : getResources().getDimensionPixelSize(
1058 com.android.internal.R.dimen.navigation_bar_height);
1059 int frameHeight = getResources().getDimensionPixelSize(
1060 com.android.internal.R.dimen.navigation_bar_frame_height);
1061 mBarTransitions.setBackgroundFrame(new Rect(0, frameHeight - height, w, h));
1062 }
1063
Matthew Ngff638122019-03-21 17:17:18 -07001064 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Daniel Sandler0b69b592012-01-23 21:08:36 -05001065 }
1066
Vinit Nayak3f35db52019-08-08 17:31:48 -07001067 private int getNavBarHeight() {
1068 return mIsVertical
1069 ? getResources().getDimensionPixelSize(
1070 com.android.internal.R.dimen.navigation_bar_height_landscape)
1071 : getResources().getDimensionPixelSize(
1072 com.android.internal.R.dimen.navigation_bar_height);
1073 }
1074
Selim Cinek92d892c2014-09-11 15:11:00 +02001075 private void notifyVerticalChangedListener(boolean newVertical) {
1076 if (mOnVerticalChangedListener != null) {
1077 mOnVerticalChangedListener.onVerticalChanged(newVertical);
1078 }
1079 }
1080
Selim Cinek17a327a2014-08-25 15:03:48 +02001081 @Override
1082 protected void onConfigurationChanged(Configuration newConfig) {
1083 super.onConfigurationChanged(newConfig);
Matthew Ng8c056c12018-10-15 15:16:46 -07001084 mTmpLastConfiguration.updateFrom(mConfiguration);
1085 mConfiguration.updateFrom(newConfig);
1086 boolean uiCarModeChanged = updateCarMode();
Matthew Ng8c056c12018-10-15 15:16:46 -07001087 updateIcons(mTmpLastConfiguration);
Winsonfde2e6a2016-03-22 16:03:10 -07001088 updateRecentsIcon();
Matthew Ng8c056c12018-10-15 15:16:46 -07001089 mRecentsOnboarding.onConfigurationChanged(mConfiguration);
1090 if (uiCarModeChanged || mTmpLastConfiguration.densityDpi != mConfiguration.densityDpi
1091 || mTmpLastConfiguration.getLayoutDirection() != mConfiguration.getLayoutDirection()) {
Jorim Jaggi11c62e12016-04-05 20:41:21 -07001092 // If car mode or density changes, we need to reset the icons.
Matthew Ngd0a73e72018-03-02 15:16:03 -08001093 updateNavButtonIcons();
Jorim Jaggi11c62e12016-04-05 20:41:21 -07001094 }
Sriram Viswanathan9ebbe6a2015-11-16 17:59:22 -08001095 }
1096
1097 /**
1098 * If the configuration changed, update the carmode and return that it was updated.
1099 */
Matthew Ng8c056c12018-10-15 15:16:46 -07001100 private boolean updateCarMode() {
Sriram Viswanathan9ebbe6a2015-11-16 17:59:22 -08001101 boolean uiCarModeChanged = false;
Matthew Ng8c056c12018-10-15 15:16:46 -07001102 if (mConfiguration != null) {
1103 int uiMode = mConfiguration.uiMode & Configuration.UI_MODE_TYPE_MASK;
Justin Paupore01915a12016-09-28 17:41:26 -07001104 final boolean isCarMode = (uiMode == Configuration.UI_MODE_TYPE_CAR);
1105
1106 if (isCarMode != mInCarMode) {
1107 mInCarMode = isCarMode;
Justin Paupore01915a12016-09-28 17:41:26 -07001108 if (ALTERNATE_CAR_MODE_UI) {
1109 mUseCarModeUi = isCarMode;
1110 uiCarModeChanged = true;
1111 } else {
1112 // Don't use car mode behavior if ALTERNATE_CAR_MODE_UI not set.
1113 mUseCarModeUi = false;
1114 }
Sriram Viswanathan9ebbe6a2015-11-16 17:59:22 -08001115 }
1116 }
1117 return uiCarModeChanged;
Selim Cinek17a327a2014-08-25 15:03:48 +02001118 }
1119
Daniel Sandler48852952011-12-01 14:34:23 -05001120 private String getResourceName(int resId) {
1121 if (resId != 0) {
John Spurlock01534782014-01-13 11:59:22 -05001122 final android.content.res.Resources res = getContext().getResources();
Daniel Sandler48852952011-12-01 14:34:23 -05001123 try {
1124 return res.getResourceName(resId);
1125 } catch (android.content.res.Resources.NotFoundException ex) {
1126 return "(unknown)";
1127 }
1128 } else {
1129 return "(null)";
1130 }
1131 }
1132
1133 private static String visibilityToString(int vis) {
1134 switch (vis) {
1135 case View.INVISIBLE:
1136 return "INVISIBLE";
1137 case View.GONE:
1138 return "GONE";
1139 default:
1140 return "VISIBLE";
1141 }
1142 }
1143
Jason Monk67e6c802016-08-30 14:09:21 -04001144 @Override
1145 protected void onAttachedToWindow() {
1146 super.onAttachedToWindow();
Adrian Roos7e58a082018-03-09 16:40:56 +01001147 requestApplyInsets();
Siarhei Vishniakoufdb42772017-06-29 10:32:11 -07001148 reorient();
Tracy Zhouefc34662019-04-22 13:37:12 -07001149 onNavigationModeChanged(mNavBarMode);
Winson Chungf9e30272018-03-26 17:25:36 -07001150 setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
Tracy Zhoucb0362a2019-06-18 10:59:11 -07001151 if (mRotationButtonController != null) {
1152 mRotationButtonController.registerListeners();
1153 }
Matthew Ngb831fb42019-01-30 11:20:48 -08001154
Sunny Goyala6a58122019-04-02 10:20:29 -07001155 mEdgeBackGestureHandler.onNavBarAttached();
Tracy Zhouefc34662019-04-22 13:37:12 -07001156 getViewTreeObserver().addOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
Jason Monk67e6c802016-08-30 14:09:21 -04001157 }
1158
1159 @Override
1160 protected void onDetachedFromWindow() {
1161 super.onDetachedFromWindow();
Winson Chung1aa24b92019-04-24 15:17:33 -07001162 Dependency.get(NavigationModeController.class).removeListener(this);
Tony Wickhamfb63fe82018-01-16 12:14:06 -08001163 setUpSwipeUpOnboarding(false);
Matthew Ng761562d2018-09-17 11:13:21 -07001164 for (int i = 0; i < mButtonDispatchers.size(); ++i) {
1165 mButtonDispatchers.valueAt(i).onDestroy();
1166 }
Tracy Zhoucb0362a2019-06-18 10:59:11 -07001167 if (mRotationButtonController != null) {
1168 mRotationButtonController.unregisterListeners();
1169 }
1170
Sunny Goyala6a58122019-04-02 10:20:29 -07001171 mEdgeBackGestureHandler.onNavBarDetached();
Tracy Zhouefc34662019-04-22 13:37:12 -07001172 getViewTreeObserver().removeOnComputeInternalInsetsListener(
1173 mOnComputeInternalInsetsListener);
Tony Wickhamfb63fe82018-01-16 12:14:06 -08001174 }
1175
1176 private void setUpSwipeUpOnboarding(boolean connectedToOverviewProxy) {
1177 if (connectedToOverviewProxy) {
Tony Wickham05c1f852018-02-06 12:32:54 -08001178 mRecentsOnboarding.onConnectedToLauncher();
Tony Wickhamfb63fe82018-01-16 12:14:06 -08001179 } else {
Tony Wickham05c1f852018-02-06 12:32:54 -08001180 mRecentsOnboarding.onDisconnectedFromLauncher();
Tony Wickhamfb63fe82018-01-16 12:14:06 -08001181 }
Jason Monk67e6c802016-08-30 14:09:21 -04001182 }
1183
Daniel Sandler48852952011-12-01 14:34:23 -05001184 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1185 pw.println("NavigationBarView {");
1186 final Rect r = new Rect();
Jeff Browna8b9def2012-07-23 14:22:49 -07001187 final Point size = new Point();
Jeff Chang2aaa91a2018-11-08 18:04:16 +08001188 getContextDisplay().getRealSize(size);
Daniel Sandler48852952011-12-01 14:34:23 -05001189
Jason Monk2a6ea9c2017-01-26 11:14:51 -05001190 pw.println(String.format(" this: " + StatusBar.viewInfo(this)
Daniel Sandler48852952011-12-01 14:34:23 -05001191 + " " + visibilityToString(getVisibility())));
1192
1193 getWindowVisibleDisplayFrame(r);
Jeff Browna8b9def2012-07-23 14:22:49 -07001194 final boolean offscreen = r.right > size.x || r.bottom > size.y;
John Spurlock209bede2013-07-17 12:23:27 -04001195 pw.println(" window: "
Daniel Sandler48852952011-12-01 14:34:23 -05001196 + r.toShortString()
1197 + " " + visibilityToString(getWindowVisibility())
1198 + (offscreen ? " OFFSCREEN!" : ""));
1199
Winson Chung661d5f92018-05-21 18:41:39 -07001200 pw.println(String.format(" mCurrentView: id=%s (%dx%d) %s %f",
Rakesh Iyerf51fe4e2016-02-09 10:51:50 -08001201 getResourceName(getCurrentView().getId()),
1202 getCurrentView().getWidth(), getCurrentView().getHeight(),
Winson Chung661d5f92018-05-21 18:41:39 -07001203 visibilityToString(getCurrentView().getVisibility()),
1204 getCurrentView().getAlpha()));
Daniel Sandler48852952011-12-01 14:34:23 -05001205
Sunny Goyalded62f02019-05-01 14:35:49 -07001206 pw.println(String.format(" disabled=0x%08x vertical=%s darkIntensity=%.2f",
Daniel Sandler48852952011-12-01 14:34:23 -05001207 mDisabledFlags,
Charles Chenaa94d95b2019-02-19 14:18:19 +08001208 mIsVertical ? "true" : "false",
Matthew Ngeb0b0942018-10-12 16:42:11 -07001209 getLightTransitionsController().getCurrentDarkIntensity()));
Daniel Sandler48852952011-12-01 14:34:23 -05001210
Vinit Nayakd2fe92f2020-06-04 13:12:02 -07001211 pw.println(" mOrientedHandleSamplingRegion: " + mOrientedHandleSamplingRegion);
1212
John Spurlock56d007b2013-10-28 18:40:56 -04001213 dumpButton(pw, "back", getBackButton());
1214 dumpButton(pw, "home", getHomeButton());
1215 dumpButton(pw, "rcnt", getRecentsButton());
Matthew Ng25593cc2018-09-12 16:05:41 -07001216 dumpButton(pw, "rota", getRotateSuggestionButton());
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001217 dumpButton(pw, "a11y", getAccessibilityButton());
Daniel Sandler48852952011-12-01 14:34:23 -05001218
Daniel Sandler48852952011-12-01 14:34:23 -05001219 pw.println(" }");
Matthew Ng25593cc2018-09-12 16:05:41 -07001220
Winson Chung7379e252020-05-29 16:01:18 -07001221 if (mNavigationInflaterView != null) {
1222 mNavigationInflaterView.dump(pw);
1223 }
Matthew Ng25593cc2018-09-12 16:05:41 -07001224 mContextualButtonGroup.dump(pw);
1225 mRecentsOnboarding.dump(pw);
Vinit Nayak3f35db52019-08-08 17:31:48 -07001226 mRegionSamplingHelper.dump(pw);
Winson Chung316f6732019-06-14 09:31:46 -07001227 mEdgeBackGestureHandler.dump(pw);
Daniel Sandler48852952011-12-01 14:34:23 -05001228 }
Jim Millere898ac52012-04-06 17:10:57 -07001229
Adrian Roos7e58a082018-03-09 16:40:56 +01001230 @Override
1231 public WindowInsets onApplyWindowInsets(WindowInsets insets) {
Selim Cineke50b1212019-06-04 18:40:31 -07001232 int leftInset = insets.getSystemWindowInsetLeft();
1233 int rightInset = insets.getSystemWindowInsetRight();
1234 setPadding(leftInset, insets.getSystemWindowInsetTop(), rightInset,
1235 insets.getSystemWindowInsetBottom());
1236 // we're passing the insets onto the gesture handler since the back arrow is only
1237 // conditionally added and doesn't always get all the insets.
1238 mEdgeBackGestureHandler.setInsets(leftInset, rightInset);
shawnlin2624bec2019-10-07 16:43:21 +08001239
1240 // this allows assist handle to be drawn outside its bound so that it can align screen
1241 // bottom by translating its y position.
1242 final boolean shouldClip =
1243 !isGesturalMode(mNavBarMode) || insets.getSystemWindowInsetBottom() == 0;
1244 setClipChildren(shouldClip);
1245 setClipToPadding(shouldClip);
1246
Govinda Wassermana596ca32019-10-16 10:09:44 -04001247 NavigationBarController navigationBarController =
1248 Dependency.get(NavigationBarController.class);
1249 AssistHandleViewController controller =
1250 navigationBarController == null
1251 ? null : navigationBarController.getAssistHandlerViewController();
shawnlin2624bec2019-10-07 16:43:21 +08001252 if (controller != null) {
1253 controller.setBottomOffset(insets.getSystemWindowInsetBottom());
1254 }
Adrian Roos7e58a082018-03-09 16:40:56 +01001255 return super.onApplyWindowInsets(insets);
1256 }
1257
Jason Monka2081822016-01-18 14:41:03 -05001258 private static void dumpButton(PrintWriter pw, String caption, ButtonDispatcher button) {
John Spurlock56d007b2013-10-28 18:40:56 -04001259 pw.print(" " + caption + ": ");
1260 if (button == null) {
1261 pw.print("null");
1262 } else {
Jason Monka2081822016-01-18 14:41:03 -05001263 pw.print(visibilityToString(button.getVisibility())
John Spurlock56d007b2013-10-28 18:40:56 -04001264 + " alpha=" + button.getAlpha()
1265 );
John Spurlock56d007b2013-10-28 18:40:56 -04001266 }
1267 pw.println();
1268 }
1269
Jorim Jaggif4797922014-08-04 22:49:41 +02001270 public interface OnVerticalChangedListener {
1271 void onVerticalChanged(boolean isVertical);
1272 }
Jason Monka2081822016-01-18 14:41:03 -05001273
Matthew Ngff638122019-03-21 17:17:18 -07001274 private final Consumer<Boolean> mDockedListener = exists -> post(() -> {
Jason Monk32e3bb52017-07-27 12:35:41 -04001275 mDockedStackExists = exists;
1276 updateRecentsIcon();
1277 });
Daniel Sandler8956dbb2011-04-22 07:55:02 -04001278}