blob: 7e81947145a66203fb72738a8bf5a10b81be2721 [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
Winson Chung1aa24b92019-04-24 15:17:33 -070019import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
Gus Prevasab336792018-11-14 13:52:20 -050020
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;
Winson Chungc4e06202018-02-13 10:37:35 -080029
John Spurlock1bbd49d2012-10-19 11:09:32 -040030import android.animation.LayoutTransition;
John Spurlock56d007b2013-10-28 18:40:56 -040031import android.animation.LayoutTransition.TransitionListener;
32import android.animation.ObjectAnimator;
Matthew Ngca4592b2018-08-06 14:12:37 -070033import android.animation.PropertyValuesHolder;
John Spurlock56d007b2013-10-28 18:40:56 -040034import android.animation.TimeInterpolator;
35import android.animation.ValueAnimator;
Jorim Jaggi40db0292016-06-27 17:58:03 -070036import android.annotation.DrawableRes;
Daniel Sandler328310c2011-09-23 15:56:52 -040037import android.app.StatusBarManager;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040038import android.content.Context;
Selim Cinek17a327a2014-08-25 15:03:48 +020039import android.content.res.Configuration;
Matthew Nga8f24262017-12-19 11:54:24 -080040import android.graphics.Canvas;
Jeff Browna8b9def2012-07-23 14:22:49 -070041import android.graphics.Point;
Daniel Sandler48852952011-12-01 14:34:23 -050042import android.graphics.Rect;
Sunny Goyalaac6c882019-02-11 11:57:58 -080043import android.graphics.Region;
44import android.graphics.Region.Op;
Matthew Ng44b14502018-05-04 11:10:14 -070045import android.os.Bundle;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040046import android.util.AttributeSet;
John Spurlockcd686b52013-06-05 10:13:46 -040047import android.util.Log;
Jason Monka2081822016-01-18 14:41:03 -050048import android.util.SparseArray;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040049import android.view.Display;
Daniel Sandler1d4d30a2011-04-28 12:35:29 -040050import android.view.MotionEvent;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040051import android.view.Surface;
John Spurlockde84f0e2013-06-12 12:41:00 -040052import android.view.View;
John Spurlock1bbd49d2012-10-19 11:09:32 -040053import android.view.ViewGroup;
Tracy Zhouefc34662019-04-22 13:37:12 -070054import android.view.ViewTreeObserver.InternalInsetsInfo;
55import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
Adrian Roos7e58a082018-03-09 16:40:56 +010056import android.view.WindowInsets;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040057import android.view.WindowManager;
Matthew Ng44b14502018-05-04 11:10:14 -070058import android.view.accessibility.AccessibilityNodeInfo;
59import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
Jason Monkf1ff2092014-04-29 16:50:53 -040060import android.view.inputmethod.InputMethodManager;
Jason Monk86bc3312016-08-16 13:17:56 -040061import android.widget.FrameLayout;
Jason Monk67e6c802016-08-30 14:09:21 -040062
Jeff Chang2aaa91a2018-11-08 18:04:16 +080063import com.android.internal.annotations.VisibleForTesting;
Jason Monkde850bb2017-02-01 19:26:30 -050064import com.android.systemui.Dependency;
Jason Monkf85fc962017-04-19 17:13:41 -040065import com.android.systemui.DockedStackExistsListener;
Matthew Ngca4592b2018-08-06 14:12:37 -070066import com.android.systemui.Interpolators;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040067import com.android.systemui.R;
Matthew Ng44b14502018-05-04 11:10:14 -070068import com.android.systemui.SysUiServiceProvider;
Matthew Ng0548fbc2019-01-11 12:24:13 -080069import com.android.systemui.assist.AssistManager;
Gus Prevasab336792018-11-14 13:52:20 -050070import com.android.systemui.recents.OverviewProxyService;
Matthew Ng44b14502018-05-04 11:10:14 -070071import com.android.systemui.recents.Recents;
Tony Wickham05c1f852018-02-06 12:32:54 -080072import com.android.systemui.recents.RecentsOnboarding;
Matthew Ng87cbf342018-02-15 12:21:18 -080073import com.android.systemui.shared.system.ActivityManagerWrapper;
Winson Chunge108b672019-03-06 16:11:28 -080074import com.android.systemui.shared.system.QuickStepContract;
Matthew Ng84db1612018-04-17 16:48:21 -070075import com.android.systemui.shared.system.WindowManagerWrapper;
Daniel Sandlerc26185b2012-08-29 15:49:53 -040076import com.android.systemui.statusbar.policy.DeadZone;
Jorim Jaggi40db0292016-06-27 17:58:03 -070077import com.android.systemui.statusbar.policy.KeyButtonDrawable;
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070078
John Spurlockde84f0e2013-06-12 12:41:00 -040079import java.io.FileDescriptor;
80import java.io.PrintWriter;
Jason Monk32e3bb52017-07-27 12:35:41 -040081import java.util.function.Consumer;
John Spurlockde84f0e2013-06-12 12:41:00 -040082
Matthew Nge0d5ccd32019-05-08 15:13:22 -070083public class NavigationBarView extends FrameLayout implements
Winson Chung1aa24b92019-04-24 15:17:33 -070084 NavigationModeController.ModeChangedListener {
Daniel Sandler60ee2562011-07-22 12:34:33 -040085 final static boolean DEBUG = false;
Adrian Roosa98b32c2016-08-11 10:41:08 -070086 final static String TAG = "StatusBar/NavBarView";
Daniel Sandler60ee2562011-07-22 12:34:33 -040087
Daniel Sandlerc3fc3222012-10-25 13:28:33 -040088 // slippery nav bar when everything is disabled, e.g. during setup
John Spurlock7edfbca2013-09-14 11:58:55 -040089 final static boolean SLIPPERY_WHEN_DISABLED = true;
Daniel Sandlerc3fc3222012-10-25 13:28:33 -040090
Justin Paupore01915a12016-09-28 17:41:26 -070091 final static boolean ALTERNATE_CAR_MODE_UI = false;
92
Daniel Sandler5c8da942011-06-28 00:29:04 -040093 View mCurrentView = null;
Charles Chenaa94d95b2019-02-19 14:18:19 +080094 private View mVertical;
95 private View mHorizontal;
Daniel Sandler60ee2562011-07-22 12:34:33 -040096
Charles Chenaa94d95b2019-02-19 14:18:19 +080097 /** Indicates that navigation bar is vertical. */
98 private boolean mIsVertical;
Adrian Roos090b7d82016-08-02 18:36:12 -070099 private int mCurrentRotation = -1;
Daniel Sandler60ee2562011-07-22 12:34:33 -0400100
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800101 boolean mLongClickableAccessibilityButton;
Daniel Sandler6da2b762011-09-14 16:04:59 -0400102 int mDisabledFlags = 0;
Daniel Sandler328310c2011-09-23 15:56:52 -0400103 int mNavigationIconHints = 0;
Winson Chung1aa24b92019-04-24 15:17:33 -0700104 private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400105
Winson Chungc4e06202018-02-13 10:37:35 -0800106 private Rect mHomeButtonBounds = new Rect();
107 private Rect mBackButtonBounds = new Rect();
Matthew Ng8a8c89c2018-03-01 13:21:43 -0800108 private Rect mRecentsButtonBounds = new Rect();
Winson Chung8079af72018-05-10 11:12:55 -0700109 private Rect mRotationButtonBounds = new Rect();
Sunny Goyalaac6c882019-02-11 11:57:58 -0800110 private final Region mActiveRegion = new Region();
Winson Chungc4e06202018-02-13 10:37:35 -0800111 private int[] mTmpPosition = new int[2];
112
Matthew Ngeb5ce832018-05-15 17:50:37 -0700113 private KeyButtonDrawable mBackIcon;
Matthew Ngec5b8412018-08-22 10:45:08 -0700114 private KeyButtonDrawable mHomeDefaultIcon;
Jorim Jaggi40db0292016-06-27 17:58:03 -0700115 private KeyButtonDrawable mRecentIcon;
116 private KeyButtonDrawable mDockedIcon;
Fabrice Di Meglio18d98242013-01-17 10:57:40 -0800117
Sunny Goyala6a58122019-04-02 10:20:29 -0700118 private final EdgeBackGestureHandler mEdgeBackGestureHandler;
Matthew Ng603b3292018-03-30 17:15:39 -0700119 private final DeadZone mDeadZone;
Matthew Ng1e14e962018-05-03 12:51:43 -0700120 private boolean mDeadZoneConsuming = false;
John Spurlock89835dd2013-08-16 15:06:51 -0400121 private final NavigationBarTransitions mBarTransitions;
Matthew Ngdc79e5c2017-12-14 17:37:35 -0800122 private final OverviewProxyService mOverviewProxyService;
Jim Millere898ac52012-04-06 17:10:57 -0700123
John Spurlock56d007b2013-10-28 18:40:56 -0400124 // performs manual animation in sync with layout transitions
125 private final NavTransitionListener mTransitionListener = new NavTransitionListener();
126
Jorim Jaggif4797922014-08-04 22:49:41 +0200127 private OnVerticalChangedListener mOnVerticalChangedListener;
Jorim Jaggi37c11802015-08-18 20:27:54 -0700128 private boolean mLayoutTransitionsEnabled = true;
129 private boolean mWakeAndUnlocking;
Justin Paupore01915a12016-09-28 17:41:26 -0700130 private boolean mUseCarModeUi = false;
131 private boolean mInCarMode = false;
Jorim Jaggid30d95d2016-02-17 20:27:22 -0800132 private boolean mDockedStackExists;
Matthew Ngf03c3a62019-04-03 13:52:57 -0700133 private boolean mImeVisible;
Jorim Jaggif4797922014-08-04 22:49:41 +0200134
Felipe Leme15f915c2016-10-31 12:47:15 -0700135 private final SparseArray<ButtonDispatcher> mButtonDispatchers = new SparseArray<>();
Matthew Ng25593cc2018-09-12 16:05:41 -0700136 private final ContextualButtonGroup mContextualButtonGroup;
Winsonfde2e6a2016-03-22 16:03:10 -0700137 private Configuration mConfiguration;
Matthew Ng8c056c12018-10-15 15:16:46 -0700138 private Configuration mTmpLastConfiguration;
Jason Monka2081822016-01-18 14:41:03 -0500139
Adrian Roosdb12b152016-07-12 15:38:55 -0700140 private NavigationBarInflaterView mNavigationInflaterView;
Tony Wickham05c1f852018-02-06 12:32:54 -0800141 private RecentsOnboarding mRecentsOnboarding;
Matthew Ng78f88d12018-01-23 12:39:55 -0800142 private NotificationPanelView mPanelView;
Tracy Zhou24fd0282019-05-20 14:40:38 -0700143 private FloatingRotationButton mFloatingRotationButton;
144 private RotationButtonController mRotationButtonController;
Adrian Roosdb12b152016-07-12 15:38:55 -0700145
Winson Chung775d2872019-03-27 14:14:01 -0700146 private NavBarTintController mTintController;
Matthew Ngb831fb42019-01-30 11:20:48 -0800147
Matthew Ng20136e62018-05-30 12:20:31 -0700148 /**
149 * Helper that is responsible for showing the right toast when a disallowed activity operation
150 * occurred. In pinned mode, we show instructions on how to break out of this mode, whilst in
151 * fully locked mode we only show that unlocking is blocked.
152 */
153 private ScreenPinningNotify mScreenPinningNotify;
154
John Spurlock56d007b2013-10-28 18:40:56 -0400155 private class NavTransitionListener implements TransitionListener {
156 private boolean mBackTransitioning;
157 private boolean mHomeAppearing;
158 private long mStartDelay;
159 private long mDuration;
160 private TimeInterpolator mInterpolator;
161
162 @Override
163 public void startTransition(LayoutTransition transition, ViewGroup container,
164 View view, int transitionType) {
165 if (view.getId() == R.id.back) {
166 mBackTransitioning = true;
167 } else if (view.getId() == R.id.home && transitionType == LayoutTransition.APPEARING) {
168 mHomeAppearing = true;
169 mStartDelay = transition.getStartDelay(transitionType);
170 mDuration = transition.getDuration(transitionType);
171 mInterpolator = transition.getInterpolator(transitionType);
172 }
173 }
174
175 @Override
176 public void endTransition(LayoutTransition transition, ViewGroup container,
177 View view, int transitionType) {
178 if (view.getId() == R.id.back) {
179 mBackTransitioning = false;
180 } else if (view.getId() == R.id.home && transitionType == LayoutTransition.APPEARING) {
181 mHomeAppearing = false;
182 }
183 }
184
185 public void onBackAltCleared() {
Jason Monka2081822016-01-18 14:41:03 -0500186 ButtonDispatcher backButton = getBackButton();
Anthony Chenada13042016-01-19 16:57:20 -0800187
John Spurlock56d007b2013-10-28 18:40:56 -0400188 // When dismissing ime during unlock, force the back button to run the same appearance
189 // animation as home (if we catch this condition early enough).
Jason Monka2081822016-01-18 14:41:03 -0500190 if (!mBackTransitioning && backButton.getVisibility() == VISIBLE
191 && mHomeAppearing && getHomeButton().getAlpha() == 0) {
John Spurlock56d007b2013-10-28 18:40:56 -0400192 getBackButton().setAlpha(0);
Anthony Chenada13042016-01-19 16:57:20 -0800193 ValueAnimator a = ObjectAnimator.ofFloat(backButton, "alpha", 0, 1);
John Spurlock56d007b2013-10-28 18:40:56 -0400194 a.setStartDelay(mStartDelay);
195 a.setDuration(mDuration);
196 a.setInterpolator(mInterpolator);
197 a.start();
198 }
199 }
200 }
201
Jason Monkf1ff2092014-04-29 16:50:53 -0400202 private final OnClickListener mImeSwitcherClickListener = new OnClickListener() {
203 @Override
204 public void onClick(View view) {
lumark0b05f9e2018-11-26 15:09:06 +0800205 mContext.getSystemService(InputMethodManager.class).showInputMethodPickerFromSystem(
206 true /* showAuxiliarySubtypes */, getContext().getDisplayId());
Jason Monkf1ff2092014-04-29 16:50:53 -0400207 }
208 };
209
Matthew Ng44b14502018-05-04 11:10:14 -0700210 private final AccessibilityDelegate mQuickStepAccessibilityDelegate
211 = new AccessibilityDelegate() {
212 private AccessibilityAction mToggleOverviewAction;
213
214 @Override
215 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
216 super.onInitializeAccessibilityNodeInfo(host, info);
217 if (mToggleOverviewAction == null) {
218 mToggleOverviewAction = new AccessibilityAction(R.id.action_toggle_overview,
219 getContext().getString(R.string.quick_step_accessibility_toggle_overview));
220 }
221 info.addAction(mToggleOverviewAction);
222 }
223
224 @Override
225 public boolean performAccessibilityAction(View host, int action, Bundle args) {
Jason Monk05dd5672018-08-09 09:38:21 -0400226 if (action == R.id.action_toggle_overview) {
227 SysUiServiceProvider.getComponent(getContext(), Recents.class)
228 .toggleRecentApps();
229 } else {
230 return super.performAccessibilityAction(host, action, args);
Matthew Ng44b14502018-05-04 11:10:14 -0700231 }
232 return true;
233 }
234 };
235
Tracy Zhouefc34662019-04-22 13:37:12 -0700236 private final OnComputeInternalInsetsListener mOnComputeInternalInsetsListener = info -> {
237 // When the nav bar is in 2-button or 3-button mode, or when IME is visible in fully
238 // gestural mode, the entire nav bar should be touchable.
Tracy Zhou24fd0282019-05-20 14:40:38 -0700239 if (!isGesturalMode(mNavBarMode) || mImeVisible) {
Tracy Zhouefc34662019-04-22 13:37:12 -0700240 info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
241 return;
242 }
Winson Chungd882ce12019-06-05 09:57:01 -0700243
Tracy Zhouefc34662019-04-22 13:37:12 -0700244 info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
Winson Chungd882ce12019-06-05 09:57:01 -0700245 ButtonDispatcher imeSwitchButton = getImeSwitchButton();
246 if (imeSwitchButton.getVisibility() == VISIBLE) {
247 // If the IME is not up, but the ime switch button is visible, then make sure that
248 // button is touchable
249 int[] loc = new int[2];
250 View buttonView = imeSwitchButton.getCurrentView();
251 buttonView.getLocationInWindow(loc);
252 info.touchableRegion.set(loc[0], loc[1], loc[0] + buttonView.getWidth(),
253 loc[1] + buttonView.getHeight());
254 return;
255 }
Tracy Zhou24fd0282019-05-20 14:40:38 -0700256 info.touchableRegion.setEmpty();
Tracy Zhouefc34662019-04-22 13:37:12 -0700257 };
258
John Spurlocke932e302013-08-12 10:16:29 -0400259 public NavigationBarView(Context context, AttributeSet attrs) {
260 super(context, attrs);
261
Charles Chenaa94d95b2019-02-19 14:18:19 +0800262 mIsVertical = false;
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800263 mLongClickableAccessibilityButton = false;
Tracy Zhouefc34662019-04-22 13:37:12 -0700264 mNavBarMode = Dependency.get(NavigationModeController.class).addListener(this);
Tracy Zhou24fd0282019-05-20 14:40:38 -0700265 boolean isGesturalMode = isGesturalMode(mNavBarMode);
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800266
Matthew Ng25593cc2018-09-12 16:05:41 -0700267 // Set up the context group of buttons
268 mContextualButtonGroup = new ContextualButtonGroup(R.id.menu_container);
Matthew Ng25593cc2018-09-12 16:05:41 -0700269 final ContextualButton imeSwitcherButton = new ContextualButton(R.id.ime_switcher,
270 R.drawable.ic_ime_switcher_default);
271 final RotationContextButton rotateSuggestionButton = new RotationContextButton(
Tracy Zhou24fd0282019-05-20 14:40:38 -0700272 R.id.rotate_suggestion, R.drawable.ic_sysbar_rotate_button);
Matthew Ng25593cc2018-09-12 16:05:41 -0700273 final ContextualButton accessibilityButton =
274 new ContextualButton(R.id.accessibility_button,
275 R.drawable.ic_sysbar_accessibility_button);
Matthew Ng25593cc2018-09-12 16:05:41 -0700276 mContextualButtonGroup.addButton(imeSwitcherButton);
Tracy Zhouefc34662019-04-22 13:37:12 -0700277 if (!isGesturalMode) {
278 mContextualButtonGroup.addButton(rotateSuggestionButton);
279 }
Matthew Ng25593cc2018-09-12 16:05:41 -0700280 mContextualButtonGroup.addButton(accessibilityButton);
281
Matthew Ngf2946542018-02-12 14:13:18 -0800282 mOverviewProxyService = Dependency.get(OverviewProxyService.class);
283 mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
Tracy Zhou24fd0282019-05-20 14:40:38 -0700284 mFloatingRotationButton = new FloatingRotationButton(context);
285 mRotationButtonController = new RotationButtonController(context,
286 R.style.RotateButtonCCWStart90,
287 isGesturalMode ? mFloatingRotationButton : rotateSuggestionButton);
Matthew Ngf2946542018-02-12 14:13:18 -0800288
Tracy Zhouefc34662019-04-22 13:37:12 -0700289 final ContextualButton backButton = new ContextualButton(R.id.back, 0);
Tracy Zhouefc34662019-04-22 13:37:12 -0700290
Winsonfde2e6a2016-03-22 16:03:10 -0700291 mConfiguration = new Configuration();
Matthew Ng8c056c12018-10-15 15:16:46 -0700292 mTmpLastConfiguration = new Configuration();
Winsonfde2e6a2016-03-22 16:03:10 -0700293 mConfiguration.updateFrom(context.getResources().getConfiguration());
John Spurlocke932e302013-08-12 10:16:29 -0400294
Matthew Ng20136e62018-05-30 12:20:31 -0700295 mScreenPinningNotify = new ScreenPinningNotify(mContext);
John Spurlock7edfbca2013-09-14 11:58:55 -0400296 mBarTransitions = new NavigationBarTransitions(this);
Jason Monka2081822016-01-18 14:41:03 -0500297
Tracy Zhouefc34662019-04-22 13:37:12 -0700298 mButtonDispatchers.put(R.id.back, backButton);
Felipe Leme15f915c2016-10-31 12:47:15 -0700299 mButtonDispatchers.put(R.id.home, new ButtonDispatcher(R.id.home));
Matthew Ngb55c02c2019-02-15 16:20:31 -0800300 mButtonDispatchers.put(R.id.home_handle, new ButtonDispatcher(R.id.home_handle));
Felipe Leme15f915c2016-10-31 12:47:15 -0700301 mButtonDispatchers.put(R.id.recent_apps, new ButtonDispatcher(R.id.recent_apps));
Matthew Ng25593cc2018-09-12 16:05:41 -0700302 mButtonDispatchers.put(R.id.ime_switcher, imeSwitcherButton);
303 mButtonDispatchers.put(R.id.accessibility_button, accessibilityButton);
304 mButtonDispatchers.put(R.id.rotate_suggestion, rotateSuggestionButton);
305 mButtonDispatchers.put(R.id.menu_container, mContextualButtonGroup);
Matthew Ng603b3292018-03-30 17:15:39 -0700306 mDeadZone = new DeadZone(this);
Matthew Ng86a436e2018-10-26 16:00:53 -0700307
Winson Chung04ff8bda2019-04-02 15:08:59 -0700308 mEdgeBackGestureHandler = new EdgeBackGestureHandler(context, mOverviewProxyService);
Winson Chung775d2872019-03-27 14:14:01 -0700309 mTintController = new NavBarTintController(this, getLightTransitionsController());
Matthew Ng355fe212018-12-14 17:42:38 -0800310 }
311
Winson Chung775d2872019-03-27 14:14:01 -0700312 public NavBarTintController getTintController() {
313 return mTintController;
John Spurlocke932e302013-08-12 10:16:29 -0400314 }
315
James O'Leary4335c702019-05-29 12:38:51 -0400316 public NavigationBarTransitions getBarTransitions() {
John Spurlocke932e302013-08-12 10:16:29 -0400317 return mBarTransitions;
318 }
319
Jorim Jaggi40db0292016-06-27 17:58:03 -0700320 public LightBarTransitionsController getLightTransitionsController() {
321 return mBarTransitions.getLightTransitionsController();
322 }
323
Matthew Ng0548fbc2019-01-11 12:24:13 -0800324 public void setComponents(NotificationPanelView panel, AssistManager assistManager) {
Matthew Ng78f88d12018-01-23 12:39:55 -0800325 mPanelView = panel;
Winson Chung56a667b2019-07-30 13:51:27 -0700326 updatePanelSystemUiStateFlags();
Matthew Ng1cf6eac2018-11-27 15:06:55 -0800327 }
328
Winson Chung600c1862019-03-07 15:14:49 -0800329 @Override
330 protected void dispatchDraw(Canvas canvas) {
331 super.dispatchDraw(canvas);
Winson Chung775d2872019-03-27 14:14:01 -0700332 mTintController.onDraw();
Winson Chung600c1862019-03-07 15:14:49 -0800333 }
334
Jorim Jaggif4797922014-08-04 22:49:41 +0200335 public void setOnVerticalChangedListener(OnVerticalChangedListener onVerticalChangedListener) {
336 mOnVerticalChangedListener = onVerticalChangedListener;
Charles Chenaa94d95b2019-02-19 14:18:19 +0800337 notifyVerticalChangedListener(mIsVertical);
Jorim Jaggif4797922014-08-04 22:49:41 +0200338 }
339
Jim Millere898ac52012-04-06 17:10:57 -0700340 @Override
341 public boolean onInterceptTouchEvent(MotionEvent event) {
Sunny Goyala6a58122019-04-02 10:20:29 -0700342 return shouldDeadZoneConsumeTouchEvents(event) || super.onInterceptTouchEvent(event);
Jim Millere898ac52012-04-06 17:10:57 -0700343 }
344
Winson Chung4faf38a2018-02-06 08:53:37 -0800345 @Override
346 public boolean onTouchEvent(MotionEvent event) {
Matthew Ng472d3e42018-06-14 15:16:55 -0700347 shouldDeadZoneConsumeTouchEvents(event);
Winson Chung49658842018-02-08 12:52:21 -0800348 return super.onTouchEvent(event);
Winson Chung4faf38a2018-02-06 08:53:37 -0800349 }
350
Winson Chung3d6c0802019-10-04 10:37:12 -0700351 void onSystemUiVisibilityChanged(int systemUiVisibility) {
352 mEdgeBackGestureHandler.onSystemUiVisibilityChanged(systemUiVisibility);
353 }
354
Winson Chung775d2872019-03-27 14:14:01 -0700355 void onBarTransition(int newMode) {
356 if (newMode == MODE_OPAQUE) {
357 // If the nav bar background is opaque, stop auto tinting since we know the icons are
358 // showing over a dark background
359 mTintController.stop();
360 getLightTransitionsController().setIconsDark(false /* dark */, true /* animate */);
361 } else {
362 mTintController.start();
363 }
364 }
365
Matthew Ng1e14e962018-05-03 12:51:43 -0700366 private boolean shouldDeadZoneConsumeTouchEvents(MotionEvent event) {
Sunny Goyala6a58122019-04-02 10:20:29 -0700367 int action = event.getActionMasked();
368 if (action == MotionEvent.ACTION_DOWN) {
369 mDeadZoneConsuming = false;
370 }
Matthew Ng1e14e962018-05-03 12:51:43 -0700371 if (mDeadZone.onTouchEvent(event) || mDeadZoneConsuming) {
Sunny Goyala6a58122019-04-02 10:20:29 -0700372 switch (action) {
Matthew Ng1e14e962018-05-03 12:51:43 -0700373 case MotionEvent.ACTION_DOWN:
374 // Allow gestures starting in the deadzone to be slippery
375 setSlippery(true);
376 mDeadZoneConsuming = true;
377 break;
378 case MotionEvent.ACTION_CANCEL:
379 case MotionEvent.ACTION_UP:
380 // When a gesture started in the deadzone is finished, restore slippery state
381 updateSlippery();
382 mDeadZoneConsuming = false;
383 break;
384 }
385 return true;
386 }
387 return false;
388 }
389
Xiyuan Xiaee7dd052015-05-15 09:46:27 -0700390 public void abortCurrentGesture() {
Jason Monka2081822016-01-18 14:41:03 -0500391 getHomeButton().abortCurrentGesture();
Xiyuan Xiaee7dd052015-05-15 09:46:27 -0700392 }
393
John Spurlock7edfbca2013-09-14 11:58:55 -0400394 public View getCurrentView() {
395 return mCurrentView;
396 }
397
Tracy Zhou24fd0282019-05-20 14:40:38 -0700398 public RotationButtonController getRotationButtonController() {
399 return mRotationButtonController;
400 }
401
402 public FloatingRotationButton getFloatingRotationButton() {
403 return mFloatingRotationButton;
404 }
405
Jason Monka2081822016-01-18 14:41:03 -0500406 public ButtonDispatcher getRecentsButton() {
Felipe Leme15f915c2016-10-31 12:47:15 -0700407 return mButtonDispatchers.get(R.id.recent_apps);
Daniel Sandler5c8da942011-06-28 00:29:04 -0400408 }
409
Jason Monka2081822016-01-18 14:41:03 -0500410 public ButtonDispatcher getBackButton() {
Felipe Leme15f915c2016-10-31 12:47:15 -0700411 return mButtonDispatchers.get(R.id.back);
Mike Lockwoode3646dd2011-09-01 12:46:28 -0400412 }
413
Jason Monka2081822016-01-18 14:41:03 -0500414 public ButtonDispatcher getHomeButton() {
Felipe Leme15f915c2016-10-31 12:47:15 -0700415 return mButtonDispatchers.get(R.id.home);
Mike Lockwoode3646dd2011-09-01 12:46:28 -0400416 }
417
Jason Monka2081822016-01-18 14:41:03 -0500418 public ButtonDispatcher getImeSwitchButton() {
Felipe Leme15f915c2016-10-31 12:47:15 -0700419 return mButtonDispatchers.get(R.id.ime_switcher);
Jason Monkf1ff2092014-04-29 16:50:53 -0400420 }
421
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800422 public ButtonDispatcher getAccessibilityButton() {
423 return mButtonDispatchers.get(R.id.accessibility_button);
424 }
425
Matthew Ng761562d2018-09-17 11:13:21 -0700426 public RotationContextButton getRotateSuggestionButton() {
Tracy Zhouefc34662019-04-22 13:37:12 -0700427 return (RotationContextButton) mButtonDispatchers.get(R.id.rotate_suggestion);
428 }
429
Matthew Ngb55c02c2019-02-15 16:20:31 -0800430 public ButtonDispatcher getHomeHandle() {
431 return mButtonDispatchers.get(R.id.home_handle);
432 }
433
Jorim Jaggi40db0292016-06-27 17:58:03 -0700434 public SparseArray<ButtonDispatcher> getButtonDispatchers() {
435 return mButtonDispatchers;
436 }
437
Matthew Ng9c3bce52018-02-01 22:00:31 +0000438 public boolean isRecentsButtonVisible() {
439 return getRecentsButton().getVisibility() == View.VISIBLE;
440 }
441
Matthew Ng6ff33b72018-02-27 13:47:38 -0800442 public boolean isOverviewEnabled() {
443 return (mDisabledFlags & View.STATUS_BAR_DISABLE_RECENT) == 0;
444 }
445
Matthew Ng8f25fb962018-01-16 17:17:24 -0800446 public boolean isQuickStepSwipeUpEnabled() {
Matthew Ngc1a97b12018-03-28 14:02:00 -0700447 return mOverviewProxyService.shouldShowSwipeUpUI() && isOverviewEnabled();
Matthew Ng8f25fb962018-01-16 17:17:24 -0800448 }
449
Matthew Ngd0a73e72018-03-02 15:16:03 -0800450 private void reloadNavIcons() {
Matthew Ng8c056c12018-10-15 15:16:46 -0700451 updateIcons(Configuration.EMPTY);
Matthew Ngd0a73e72018-03-02 15:16:03 -0800452 }
453
Matthew Ng8c056c12018-10-15 15:16:46 -0700454 private void updateIcons(Configuration oldConfig) {
455 final boolean orientationChange = oldConfig.orientation != mConfiguration.orientation;
456 final boolean densityChange = oldConfig.densityDpi != mConfiguration.densityDpi;
457 final boolean dirChange = oldConfig.getLayoutDirection() != mConfiguration.getLayoutDirection();
Matthew Ngca4592b2018-08-06 14:12:37 -0700458
459 if (orientationChange || densityChange) {
Matthew Ngd6865ba2018-08-27 17:58:41 -0700460 mDockedIcon = getDrawable(R.drawable.ic_sysbar_docked);
461 mHomeDefaultIcon = getHomeDrawable();
Winsonfde2e6a2016-03-22 16:03:10 -0700462 }
Matthew Ngca4592b2018-08-06 14:12:37 -0700463 if (densityChange || dirChange) {
Matthew Ngd6865ba2018-08-27 17:58:41 -0700464 mRecentIcon = getDrawable(R.drawable.ic_sysbar_recent);
Matthew Ng25593cc2018-09-12 16:05:41 -0700465 mContextualButtonGroup.updateIcons();
Winsonfde2e6a2016-03-22 16:03:10 -0700466 }
Matthew Ngca4592b2018-08-06 14:12:37 -0700467 if (orientationChange || densityChange || dirChange) {
Matthew Ngd6865ba2018-08-27 17:58:41 -0700468 mBackIcon = getBackDrawable();
Matthew Ngca4592b2018-08-06 14:12:37 -0700469 }
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700470 }
471
Matthew Ngd6865ba2018-08-27 17:58:41 -0700472 public KeyButtonDrawable getBackDrawable() {
Tracy Zhouefc34662019-04-22 13:37:12 -0700473 KeyButtonDrawable drawable = getDrawable(getBackDrawableRes());
Matthew Ngeb5ce832018-05-15 17:50:37 -0700474 orientBackButton(drawable);
475 return drawable;
Matthew Ng87cbf342018-02-15 12:21:18 -0800476 }
477
Tracy Zhouefc34662019-04-22 13:37:12 -0700478 public @DrawableRes int getBackDrawableRes() {
479 return chooseNavigationIconDrawableRes(R.drawable.ic_sysbar_back,
480 R.drawable.ic_sysbar_back_quick_step);
481 }
482
Matthew Ngd6865ba2018-08-27 17:58:41 -0700483 public KeyButtonDrawable getHomeDrawable() {
Matthew Ngeb5ce832018-05-15 17:50:37 -0700484 final boolean quickStepEnabled = mOverviewProxyService.shouldShowSwipeUpUI();
485 KeyButtonDrawable drawable = quickStepEnabled
Matthew Ngd6865ba2018-08-27 17:58:41 -0700486 ? getDrawable(R.drawable.ic_sysbar_home_quick_step)
487 : getDrawable(R.drawable.ic_sysbar_home);
Matthew Ngeb5ce832018-05-15 17:50:37 -0700488 orientHomeButton(drawable);
489 return drawable;
Matthew Ng87cbf342018-02-15 12:21:18 -0800490 }
491
Matthew Ngeb5ce832018-05-15 17:50:37 -0700492 private void orientBackButton(KeyButtonDrawable drawable) {
493 final boolean useAltBack =
Matthew Ngca4592b2018-08-06 14:12:37 -0700494 (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
Matthew Ng8c056c12018-10-15 15:16:46 -0700495 final boolean isRtl = mConfiguration.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
Matthew Ngd04bd0f2019-04-08 17:29:45 -0700496 float degrees = useAltBack ? (isRtl ? 90 : -90) : 0;
Matthew Ngca4592b2018-08-06 14:12:37 -0700497 if (drawable.getRotation() == degrees) {
498 return;
499 }
500
Tracy Zhou24fd0282019-05-20 14:40:38 -0700501 if (isGesturalMode(mNavBarMode)) {
Matthew Ngf03c3a62019-04-03 13:52:57 -0700502 drawable.setRotation(degrees);
503 return;
504 }
505
Matthew Ngca4592b2018-08-06 14:12:37 -0700506 // Animate the back button's rotation to the new degrees and only in portrait move up the
507 // back button to line up with the other buttons
Charles Chenaa94d95b2019-02-19 14:18:19 +0800508 float targetY = !mOverviewProxyService.shouldShowSwipeUpUI() && !mIsVertical && useAltBack
Matthew Ngca4592b2018-08-06 14:12:37 -0700509 ? - getResources().getDimension(R.dimen.navbar_back_button_ime_offset)
510 : 0;
511 ObjectAnimator navBarAnimator = ObjectAnimator.ofPropertyValuesHolder(drawable,
512 PropertyValuesHolder.ofFloat(KeyButtonDrawable.KEY_DRAWABLE_ROTATE, degrees),
513 PropertyValuesHolder.ofFloat(KeyButtonDrawable.KEY_DRAWABLE_TRANSLATE_Y, targetY));
514 navBarAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
515 navBarAnimator.setDuration(200);
516 navBarAnimator.start();
Matthew Ng87cbf342018-02-15 12:21:18 -0800517 }
518
Matthew Ngeb5ce832018-05-15 17:50:37 -0700519 private void orientHomeButton(KeyButtonDrawable drawable) {
Charles Chenaa94d95b2019-02-19 14:18:19 +0800520 drawable.setRotation(mIsVertical ? 90 : 0);
Matthew Ngeb5ce832018-05-15 17:50:37 -0700521 }
522
Matthew Ngd6865ba2018-08-27 17:58:41 -0700523 private KeyButtonDrawable chooseNavigationIconDrawable(@DrawableRes int icon,
524 @DrawableRes int quickStepIcon) {
Tracy Zhouefc34662019-04-22 13:37:12 -0700525 return getDrawable(chooseNavigationIconDrawableRes(icon, quickStepIcon));
526 }
527
528 private @DrawableRes int chooseNavigationIconDrawableRes(@DrawableRes int icon,
529 @DrawableRes int quickStepIcon) {
Matthew Ngc1a97b12018-03-28 14:02:00 -0700530 final boolean quickStepEnabled = mOverviewProxyService.shouldShowSwipeUpUI();
Tracy Zhouefc34662019-04-22 13:37:12 -0700531 return quickStepEnabled ? quickStepIcon : icon;
Matthew Ngeb5ce832018-05-15 17:50:37 -0700532 }
533
Matthew Ngd6865ba2018-08-27 17:58:41 -0700534 private KeyButtonDrawable getDrawable(@DrawableRes int icon) {
Matthew Ng25593cc2018-09-12 16:05:41 -0700535 return KeyButtonDrawable.create(mContext, icon, true /* hasShadow */);
Matthew Ngeb5ce832018-05-15 17:50:37 -0700536 }
537
Matthew Ngd6865ba2018-08-27 17:58:41 -0700538 private KeyButtonDrawable getDrawable(@DrawableRes int icon, boolean hasShadow) {
Matthew Ng25593cc2018-09-12 16:05:41 -0700539 return KeyButtonDrawable.create(mContext, icon, hasShadow);
Mike Digman7d092772018-01-11 12:10:32 -0800540 }
541
Winson Chung2102ae82019-06-19 13:15:24 -0700542 public void setWindowVisible(boolean visible) {
543 mTintController.setWindowVisible(visible);
544 mRotationButtonController.onNavigationBarWindowVisibilityChange(visible);
545 }
546
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700547 @Override
548 public void setLayoutDirection(int layoutDirection) {
Matthew Ngd0a73e72018-03-02 15:16:03 -0800549 reloadNavIcons();
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700550
551 super.setLayoutDirection(layoutDirection);
Daniel Sandler1d4d30a2011-04-28 12:35:29 -0400552 }
553
Matthew Ngd0a73e72018-03-02 15:16:03 -0800554 public void setNavigationIconHints(int hints) {
555 if (hints == mNavigationIconHints) return;
Matthew Ng691d5582019-04-04 14:59:17 -0700556 final boolean newBackAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
557 final boolean oldBackAlt =
558 (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
559 if (newBackAlt != oldBackAlt) {
560 onImeVisibilityChanged(newBackAlt);
John Spurlock56d007b2013-10-28 18:40:56 -0400561 }
Matthew Ng691d5582019-04-04 14:59:17 -0700562
Daniel Sandler328310c2011-09-23 15:56:52 -0400563 if (DEBUG) {
John Spurlock01534782014-01-13 11:59:22 -0500564 android.widget.Toast.makeText(getContext(),
Daniel Sandler328310c2011-09-23 15:56:52 -0400565 "Navigation icon hints = " + hints,
566 500).show();
567 }
Daniel Sandler328310c2011-09-23 15:56:52 -0400568 mNavigationIconHints = hints;
Matthew Ngd0a73e72018-03-02 15:16:03 -0800569 updateNavButtonIcons();
570 }
Daniel Sandler328310c2011-09-23 15:56:52 -0400571
Matthew Ng691d5582019-04-04 14:59:17 -0700572 private void onImeVisibilityChanged(boolean visible) {
573 if (!visible) {
574 mTransitionListener.onBackAltCleared();
575 }
576 mImeVisible = visible;
Tracy Zhou24fd0282019-05-20 14:40:38 -0700577 mRotationButtonController.getRotationButton().setCanShowRotationButton(!mImeVisible);
Matthew Ng691d5582019-04-04 14:59:17 -0700578 }
579
Matthew Ngd0a73e72018-03-02 15:16:03 -0800580 public void setDisabledFlags(int disabledFlags) {
581 if (mDisabledFlags == disabledFlags) return;
582
583 final boolean overviewEnabledBefore = isOverviewEnabled();
584 mDisabledFlags = disabledFlags;
585
586 // Update icons if overview was just enabled to ensure the correct icons are present
587 if (!overviewEnabledBefore && isOverviewEnabled()) {
588 reloadNavIcons();
589 }
590
591 updateNavButtonIcons();
Winson Chung1be4c7e2018-05-23 18:24:13 -0700592 updateSlippery();
Tracy Zhou98140912018-06-05 12:09:14 -0700593 setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
Winson Chung56a667b2019-07-30 13:51:27 -0700594 updateDisabledSystemUiStateFlags();
Matthew Ngd0a73e72018-03-02 15:16:03 -0800595 }
596
597 public void updateNavButtonIcons() {
Sriram Viswanathan9ebbe6a2015-11-16 17:59:22 -0800598 // We have to replace or restore the back and home button icons when exiting or entering
599 // carmode, respectively. Recents are not available in CarMode in nav bar so change
600 // to recent icon is not required.
Matthew Ngeb5ce832018-05-15 17:50:37 -0700601 final boolean useAltBack =
602 (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
Matthew Ngd6865ba2018-08-27 17:58:41 -0700603 KeyButtonDrawable backIcon = mBackIcon;
Matthew Ngec5b8412018-08-22 10:45:08 -0700604 orientBackButton(backIcon);
Matthew Ngd6865ba2018-08-27 17:58:41 -0700605 KeyButtonDrawable homeIcon = mHomeDefaultIcon;
Matthew Ngeb5ce832018-05-15 17:50:37 -0700606 if (!mUseCarModeUi) {
Matthew Ngeb5ce832018-05-15 17:50:37 -0700607 orientHomeButton(homeIcon);
608 }
609 getHomeButton().setImageDrawable(homeIcon);
Jason Monka2081822016-01-18 14:41:03 -0500610 getBackButton().setImageDrawable(backIcon);
Sriram Viswanathan9ebbe6a2015-11-16 17:59:22 -0800611
Jorim Jaggid30d95d2016-02-17 20:27:22 -0800612 updateRecentsIcon();
Sriram Viswanathan9ebbe6a2015-11-16 17:59:22 -0800613
Mike Digmana48cf192018-02-12 17:52:48 -0800614 // Update IME button visibility, a11y and rotate button always overrides the appearance
Tracy Zhouefc34662019-04-22 13:37:12 -0700615 mContextualButtonGroup.setButtonVisibility(R.id.ime_switcher,
Matthew Ng25593cc2018-09-12 16:05:41 -0700616 (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800617
Jorim Jaggi40db0292016-06-27 17:58:03 -0700618 mBarTransitions.reapplyDarkIntensity();
Daniel Sandler328310c2011-09-23 15:56:52 -0400619
Tracy Zhou24fd0282019-05-20 14:40:38 -0700620 boolean disableHome = isGesturalMode(mNavBarMode)
Winson Chunge108b672019-03-06 16:11:28 -0800621 || ((mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
Sriram Viswanathan469caae2016-03-22 13:11:50 -0700622
Jeff Chang2aaa91a2018-11-08 18:04:16 +0800623 // Always disable recents when alternate car mode UI is active and for secondary displays.
624 boolean disableRecent = isRecentsButtonDisabled();
Charles Hee57ff812017-10-26 10:01:35 +0100625
Sunny Goyalbe4e0542019-08-08 16:36:14 -0700626 // Disable the home handle if both hone and recents are disabled
627 boolean disableHomeHandle = disableRecent
628 && ((mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
629
Tracy Zhou24fd0282019-05-20 14:40:38 -0700630 boolean disableBack = !useAltBack && (isGesturalMode(mNavBarMode)
Matthew Ngf03c3a62019-04-03 13:52:57 -0700631 || ((mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0));
Daniel Sandler029d5872011-09-12 00:58:58 -0400632
Matthew Ng87cbf342018-02-15 12:21:18 -0800633 // When screen pinning, don't hide back and home when connected service or back and
634 // recents buttons when disconnected from launcher service in screen pinning mode,
635 // as they are used for exiting.
Matthew Ng6ff33b72018-02-27 13:47:38 -0800636 final boolean pinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive();
Winson Chungd95a2252018-04-04 17:02:29 +0000637 if (mOverviewProxyService.isEnabled()) {
Winson Chung30c62602019-05-09 13:34:48 -0700638 // Force disable recents when not in legacy mode
639 disableRecent |= !QuickStepContract.isLegacyMode(mNavBarMode);
Tracy Zhou63b50472019-07-01 15:27:02 -0700640 if (pinningActive && !QuickStepContract.isGesturalMode(mNavBarMode)) {
Matthew Ng87cbf342018-02-15 12:21:18 -0800641 disableBack = disableHome = false;
Matthew Ng87cbf342018-02-15 12:21:18 -0800642 }
Matthew Ng6ff33b72018-02-27 13:47:38 -0800643 } else if (pinningActive) {
Matthew Ng87cbf342018-02-15 12:21:18 -0800644 disableBack = disableRecent = false;
Matthew Ngdc79e5c2017-12-14 17:37:35 -0800645 }
Charles Hee57ff812017-10-26 10:01:35 +0100646
Winson Chunge108b672019-03-06 16:11:28 -0800647 ViewGroup navButtons = getCurrentView().findViewById(R.id.nav_buttons);
John Spurlock56d007b2013-10-28 18:40:56 -0400648 if (navButtons != null) {
649 LayoutTransition lt = navButtons.getLayoutTransition();
John Spurlock1bbd49d2012-10-19 11:09:32 -0400650 if (lt != null) {
John Spurlock56d007b2013-10-28 18:40:56 -0400651 if (!lt.getTransitionListeners().contains(mTransitionListener)) {
652 lt.addTransitionListener(mTransitionListener);
653 }
John Spurlock1bbd49d2012-10-19 11:09:32 -0400654 }
655 }
656
Jason Monka2081822016-01-18 14:41:03 -0500657 getBackButton().setVisibility(disableBack ? View.INVISIBLE : View.VISIBLE);
Jason Monk188908f2016-01-22 10:23:51 -0500658 getHomeButton().setVisibility(disableHome ? View.INVISIBLE : View.VISIBLE);
Jason Monka2081822016-01-18 14:41:03 -0500659 getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE);
Sunny Goyalbe4e0542019-08-08 16:36:14 -0700660 getHomeHandle().setVisibility(disableHomeHandle ? View.INVISIBLE : View.VISIBLE);
John Spurlock56d007b2013-10-28 18:40:56 -0400661 }
662
Jeff Chang2aaa91a2018-11-08 18:04:16 +0800663 @VisibleForTesting
664 boolean isRecentsButtonDisabled() {
665 return mUseCarModeUi || !isOverviewEnabled()
666 || getContext().getDisplayId() != Display.DEFAULT_DISPLAY;
667 }
668
669 private Display getContextDisplay() {
670 return getContext().getDisplay();
671 }
672
Jorim Jaggi37c11802015-08-18 20:27:54 -0700673 public void setLayoutTransitionsEnabled(boolean enabled) {
674 mLayoutTransitionsEnabled = enabled;
675 updateLayoutTransitionsEnabled();
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700676 }
677
Jorim Jaggi37c11802015-08-18 20:27:54 -0700678 public void setWakeAndUnlocking(boolean wakeAndUnlocking) {
679 setUseFadingAnimations(wakeAndUnlocking);
680 mWakeAndUnlocking = wakeAndUnlocking;
681 updateLayoutTransitionsEnabled();
682 }
683
684 private void updateLayoutTransitionsEnabled() {
685 boolean enabled = !mWakeAndUnlocking && mLayoutTransitionsEnabled;
Rakesh Iyer1186faa2015-12-07 16:48:46 -0800686 ViewGroup navButtons = (ViewGroup) getCurrentView().findViewById(R.id.nav_buttons);
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700687 LayoutTransition lt = navButtons.getLayoutTransition();
Julia Reynolds8478aba2015-07-31 09:17:20 -0400688 if (lt != null) {
689 if (enabled) {
690 lt.enableTransitionType(LayoutTransition.APPEARING);
691 lt.enableTransitionType(LayoutTransition.DISAPPEARING);
692 lt.enableTransitionType(LayoutTransition.CHANGE_APPEARING);
693 lt.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
694 } else {
695 lt.disableTransitionType(LayoutTransition.APPEARING);
696 lt.disableTransitionType(LayoutTransition.DISAPPEARING);
697 lt.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
698 lt.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
699 }
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700700 }
701 }
702
703 private void setUseFadingAnimations(boolean useFadingAnimations) {
Jason Monk49fa0162017-01-11 09:21:56 -0500704 WindowManager.LayoutParams lp = (WindowManager.LayoutParams) ((ViewGroup) getParent())
705 .getLayoutParams();
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700706 if (lp != null) {
707 boolean old = lp.windowAnimations != 0;
708 if (!old && useFadingAnimations) {
709 lp.windowAnimations = R.style.Animation_NavigationBarFadeIn;
710 } else if (old && !useFadingAnimations) {
711 lp.windowAnimations = 0;
712 } else {
713 return;
714 }
715 WindowManager wm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
Jason Monk49fa0162017-01-11 09:21:56 -0500716 wm.updateViewLayout((View) getParent(), lp);
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700717 }
718 }
719
Winson Chung5b6a1fe2019-07-26 16:38:08 -0700720 public void onStatusBarPanelStateChanged() {
Matthew Ng78f88d12018-01-23 12:39:55 -0800721 updateSlippery();
Winson Chung56a667b2019-07-30 13:51:27 -0700722 updatePanelSystemUiStateFlags();
Winson Chunga7067002019-05-07 11:50:42 -0700723 }
724
Winson Chung56a667b2019-07-30 13:51:27 -0700725 public void updateDisabledSystemUiStateFlags() {
Winson Chunga7067002019-05-07 11:50:42 -0700726 int displayId = mContext.getDisplayId();
727 mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_SCREEN_PINNING,
728 ActivityManagerWrapper.getInstance().isScreenPinningActive(), displayId);
729 mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_OVERVIEW_DISABLED,
730 (mDisabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0, displayId);
731 mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_HOME_DISABLED,
732 (mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0, displayId);
Winson Chungcb6454e2019-07-23 09:58:47 -0700733 mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_SEARCH_DISABLED,
734 (mDisabledFlags & View.STATUS_BAR_DISABLE_SEARCH) != 0, displayId);
Winson Chung56a667b2019-07-30 13:51:27 -0700735 }
736
737 public void updatePanelSystemUiStateFlags() {
738 int displayId = mContext.getDisplayId();
Winson Chunga7067002019-05-07 11:50:42 -0700739 if (mPanelView != null) {
740 mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
741 mPanelView.isFullyExpanded() && !mPanelView.isInSettings(), displayId);
Winson Chung5b6a1fe2019-07-26 16:38:08 -0700742 mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_QUICK_SETTINGS_EXPANDED,
743 mPanelView.isInSettings(), displayId);
Winson Chunga7067002019-05-07 11:50:42 -0700744 }
Matthew Ng78f88d12018-01-23 12:39:55 -0800745 }
746
Matthew Ng8f25fb962018-01-16 17:17:24 -0800747 public void updateStates() {
Matthew Ng44b14502018-05-04 11:10:14 -0700748 final boolean showSwipeUpUI = mOverviewProxyService.shouldShowSwipeUpUI();
Mike Digmanf77fb912018-05-21 11:21:30 -0700749
750 if (mNavigationInflaterView != null) {
751 // Reinflate the navbar if needed, no-op unless the swipe up state changes
752 mNavigationInflaterView.onLikelyDefaultLayoutChange();
753 }
754
Matthew Ng8f25fb962018-01-16 17:17:24 -0800755 updateSlippery();
Winson Chung770d7e92018-03-20 17:51:39 -0700756 reloadNavIcons();
Matthew Ngd0a73e72018-03-02 15:16:03 -0800757 updateNavButtonIcons();
Winson Chungf9e30272018-03-26 17:25:36 -0700758 setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
Matthew Ng44b14502018-05-04 11:10:14 -0700759 WindowManagerWrapper.getInstance().setNavBarVirtualKeyHapticFeedbackEnabled(!showSwipeUpUI);
760 getHomeButton().setAccessibilityDelegate(
761 showSwipeUpUI ? mQuickStepAccessibilityDelegate : null);
Matthew Ng8f25fb962018-01-16 17:17:24 -0800762 }
763
Matthew Ng90ef0632018-08-15 13:53:15 -0700764 /**
765 * Updates the {@link WindowManager.LayoutParams.FLAG_SLIPPERY} state dependent on if swipe up
766 * is enabled, or the notifications is fully opened without being in an animated state. If
767 * slippery is enabled, touch events will leave the nav bar window and enter into the fullscreen
768 * app/home window, if not nav bar will receive a cancelled touch event once gesture leaves bar.
769 */
Matthew Ng472d3e42018-06-14 15:16:55 -0700770 public void updateSlippery() {
Matthew Ng90ef0632018-08-15 13:53:15 -0700771 setSlippery(!isQuickStepSwipeUpEnabled() ||
772 (mPanelView.isFullyExpanded() && !mPanelView.isCollapsing()));
Matthew Ng78f88d12018-01-23 12:39:55 -0800773 }
774
Matthew Ng7d05e772017-11-09 14:41:07 -0800775 private void setSlippery(boolean slippery) {
Matthew Ngb831fb42019-01-30 11:20:48 -0800776 setWindowFlag(WindowManager.LayoutParams.FLAG_SLIPPERY, slippery);
777 }
778
Matthew Ngb831fb42019-01-30 11:20:48 -0800779 private void setWindowFlag(int flags, boolean enable) {
Matthew Ng7d05e772017-11-09 14:41:07 -0800780 final ViewGroup navbarView = ((ViewGroup) getParent());
Matthew Ngb55c02c2019-02-15 16:20:31 -0800781 if (navbarView == null) {
782 return;
783 }
Matthew Ngb831fb42019-01-30 11:20:48 -0800784 WindowManager.LayoutParams lp = (WindowManager.LayoutParams) navbarView.getLayoutParams();
785 if (lp == null || enable == ((lp.flags & flags) != 0)) {
Matthew Ng9c3bce52018-02-01 22:00:31 +0000786 return;
787 }
Matthew Ngb831fb42019-01-30 11:20:48 -0800788 if (enable) {
789 lp.flags |= flags;
790 } else {
791 lp.flags &= ~flags;
Matthew Ng7d05e772017-11-09 14:41:07 -0800792 }
Matthew Ngb831fb42019-01-30 11:20:48 -0800793 WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
794 wm.updateViewLayout(navbarView, lp);
Matthew Ng7d05e772017-11-09 14:41:07 -0800795 }
796
Winson Chung1aa24b92019-04-24 15:17:33 -0700797 @Override
798 public void onNavigationModeChanged(int mode) {
Winson Chung316f6732019-06-14 09:31:46 -0700799 Context curUserCtx = Dependency.get(NavigationModeController.class).getCurrentUserContext();
Winson Chung1aa24b92019-04-24 15:17:33 -0700800 mNavBarMode = mode;
801 mBarTransitions.onNavigationModeChanged(mNavBarMode);
Winson Chung316f6732019-06-14 09:31:46 -0700802 mEdgeBackGestureHandler.onNavigationModeChanged(mNavBarMode, curUserCtx);
Winson Chung1aa24b92019-04-24 15:17:33 -0700803 mRecentsOnboarding.onNavigationModeChanged(mNavBarMode);
Tracy Zhouefc34662019-04-22 13:37:12 -0700804 getRotateSuggestionButton().onNavigationModeChanged(mNavBarMode);
Matthew Ngb55c02c2019-02-15 16:20:31 -0800805
806 // Color adaption is tied with showing home handle, only avaliable if visible
Winson Chung1aa24b92019-04-24 15:17:33 -0700807 mTintController.onNavigationModeChanged(mNavBarMode);
Tracy Zhou24fd0282019-05-20 14:40:38 -0700808 if (isGesturalMode(mNavBarMode)) {
Winson Chung775d2872019-03-27 14:14:01 -0700809 mTintController.start();
Matthew Ngb55c02c2019-02-15 16:20:31 -0800810 } else {
Winson Chung775d2872019-03-27 14:14:01 -0700811 mTintController.stop();
Matthew Ngb55c02c2019-02-15 16:20:31 -0800812 }
813 }
814
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800815 public void setAccessibilityButtonState(final boolean visible, final boolean longClickable) {
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800816 mLongClickableAccessibilityButton = longClickable;
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800817 getAccessibilityButton().setLongClickable(longClickable);
Tracy Zhouefc34662019-04-22 13:37:12 -0700818 mContextualButtonGroup.setButtonVisibility(R.id.accessibility_button, visible);
Mike Digmana48cf192018-02-12 17:52:48 -0800819 }
820
Tracy Zhou1ac592c2018-07-25 13:47:37 -0700821 void hideRecentsOnboarding() {
822 mRecentsOnboarding.hide(true);
823 }
824
Jim Miller960892c2012-05-23 15:50:04 -0700825 @Override
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400826 public void onFinishInflate() {
Winson Chung661d5f92018-05-21 18:41:39 -0700827 mNavigationInflaterView = findViewById(R.id.navigation_inflater);
Felipe Leme15f915c2016-10-31 12:47:15 -0700828 mNavigationInflaterView.setButtonDispatchers(mButtonDispatchers);
Jason Monka2081822016-01-18 14:41:03 -0500829
830 getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
Selim Cinek17a327a2014-08-25 15:03:48 +0200831
Jason Monk32e3bb52017-07-27 12:35:41 -0400832 DockedStackExistsListener.register(mDockedListener);
Charles Chenaa94d95b2019-02-19 14:18:19 +0800833 updateOrientationViews();
Matthew Ng25593cc2018-09-12 16:05:41 -0700834 reloadNavIcons();
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100835 }
836
Matthew Nga8f24262017-12-19 11:54:24 -0800837 @Override
838 protected void onDraw(Canvas canvas) {
Matthew Ng603b3292018-03-30 17:15:39 -0700839 mDeadZone.onDraw(canvas);
Matthew Nga8f24262017-12-19 11:54:24 -0800840 super.onDraw(canvas);
841 }
842
843 @Override
844 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
845 super.onLayout(changed, left, top, right, bottom);
Sunny Goyalaac6c882019-02-11 11:57:58 -0800846
847 mActiveRegion.setEmpty();
848 updateButtonLocation(getBackButton(), mBackButtonBounds, true);
849 updateButtonLocation(getHomeButton(), mHomeButtonBounds, false);
850 updateButtonLocation(getRecentsButton(), mRecentsButtonBounds, false);
851 updateButtonLocation(getRotateSuggestionButton(), mRotationButtonBounds, true);
852 // TODO: Handle button visibility changes
853 mOverviewProxyService.onActiveNavBarRegionChanges(mActiveRegion);
Tracy Zhou559d97c2018-04-07 23:54:46 -0700854 mRecentsOnboarding.setNavBarHeight(getMeasuredHeight());
Matthew Nga8f24262017-12-19 11:54:24 -0800855 }
856
Sunny Goyalaac6c882019-02-11 11:57:58 -0800857 private void updateButtonLocation(ButtonDispatcher button, Rect buttonBounds,
858 boolean isActive) {
Winson Chungc4e06202018-02-13 10:37:35 -0800859 View view = button.getCurrentView();
860 if (view == null) {
861 buttonBounds.setEmpty();
862 return;
863 }
Matthew Ng3b7e3902018-03-22 16:06:09 -0700864 // Temporarily reset the translation back to origin to get the position in window
865 final float posX = view.getTranslationX();
866 final float posY = view.getTranslationY();
867 view.setTranslationX(0);
868 view.setTranslationY(0);
Sunny Goyalaac6c882019-02-11 11:57:58 -0800869
870 if (isActive) {
871 view.getLocationOnScreen(mTmpPosition);
872 buttonBounds.set(mTmpPosition[0], mTmpPosition[1],
873 mTmpPosition[0] + view.getMeasuredWidth(),
874 mTmpPosition[1] + view.getMeasuredHeight());
875 mActiveRegion.op(buttonBounds, Op.UNION);
876 }
Winson Chungc4e06202018-02-13 10:37:35 -0800877 view.getLocationInWindow(mTmpPosition);
878 buttonBounds.set(mTmpPosition[0], mTmpPosition[1],
879 mTmpPosition[0] + view.getMeasuredWidth(),
880 mTmpPosition[1] + view.getMeasuredHeight());
Matthew Ng3b7e3902018-03-22 16:06:09 -0700881 view.setTranslationX(posX);
882 view.setTranslationY(posY);
Winson Chungc4e06202018-02-13 10:37:35 -0800883 }
884
Charles Chenaa94d95b2019-02-19 14:18:19 +0800885 private void updateOrientationViews() {
886 mHorizontal = findViewById(R.id.horizontal);
887 mVertical = findViewById(R.id.vertical);
Jason Monk9a6552d2016-05-20 11:21:59 -0400888
Jason Monk199a2d02017-07-28 11:08:27 -0400889 updateCurrentView();
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400890 }
891
Charles Chenaa94d95b2019-02-19 14:18:19 +0800892 boolean needsReorient(int rotation) {
Adrian Roosa98b32c2016-08-11 10:41:08 -0700893 return mCurrentRotation != rotation;
Adrian Roos090b7d82016-08-02 18:36:12 -0700894 }
895
Jason Monk199a2d02017-07-28 11:08:27 -0400896 private void updateCurrentView() {
Charles Chenaa94d95b2019-02-19 14:18:19 +0800897 resetViews();
898 mCurrentView = mIsVertical ? mVertical : mHorizontal;
Daniel Sandler5c8da942011-06-28 00:29:04 -0400899 mCurrentView.setVisibility(View.VISIBLE);
Charles Chenaa94d95b2019-02-19 14:18:19 +0800900 mNavigationInflaterView.setVertical(mIsVertical);
901 mCurrentRotation = getContextDisplay().getRotation();
902 mNavigationInflaterView.setAlternativeOrder(mCurrentRotation == Surface.ROTATION_90);
Matthew Ng1efc9c32018-04-11 18:13:56 -0700903 mNavigationInflaterView.updateButtonDispatchersCurrentView();
Jorim Jaggi37c11802015-08-18 20:27:54 -0700904 updateLayoutTransitionsEnabled();
Charles Chenaa94d95b2019-02-19 14:18:19 +0800905 }
906
907 private void resetViews() {
908 mHorizontal.setVisibility(View.GONE);
909 mVertical.setVisibility(View.GONE);
Jason Monk9a6552d2016-05-20 11:21:59 -0400910 }
911
912 private void updateRecentsIcon() {
Charles Chenaa94d95b2019-02-19 14:18:19 +0800913 mDockedIcon.setRotation(mDockedStackExists && mIsVertical ? 90 : 0);
Jason Monk9a6552d2016-05-20 11:21:59 -0400914 getRecentsButton().setImageDrawable(mDockedStackExists ? mDockedIcon : mRecentIcon);
Jorim Jaggi40db0292016-06-27 17:58:03 -0700915 mBarTransitions.reapplyDarkIntensity();
Jason Monk9a6552d2016-05-20 11:21:59 -0400916 }
917
Matthew Ng20136e62018-05-30 12:20:31 -0700918 public void showPinningEnterExitToast(boolean entering) {
919 if (entering) {
920 mScreenPinningNotify.showPinningStartToast();
921 } else {
922 mScreenPinningNotify.showPinningExitToast();
923 }
924 }
925
926 public void showPinningEscapeToast() {
927 mScreenPinningNotify.showEscapeToast(isRecentsButtonVisible());
928 }
929
Jason Monk9a6552d2016-05-20 11:21:59 -0400930 public boolean isVertical() {
Charles Chenaa94d95b2019-02-19 14:18:19 +0800931 return mIsVertical;
Jason Monk9a6552d2016-05-20 11:21:59 -0400932 }
933
934 public void reorient() {
Jason Monk199a2d02017-07-28 11:08:27 -0400935 updateCurrentView();
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400936
Siarhei Vishniakoufdb42772017-06-29 10:32:11 -0700937 ((NavigationBarFrame) getRootView()).setDeadZone(mDeadZone);
Matthew Ng603b3292018-03-30 17:15:39 -0700938 mDeadZone.onConfigurationChanged(mCurrentRotation);
Daniel Sandlerc26185b2012-08-29 15:49:53 -0400939
Daniel Sandler6da2b762011-09-14 16:04:59 -0400940 // force the low profile & disabled states into compliance
Adrian Roos8a8ffd42015-05-26 18:30:37 -0700941 mBarTransitions.init();
Daniel Sandler6da2b762011-09-14 16:04:59 -0400942
Daniel Sandler60ee2562011-07-22 12:34:33 -0400943 if (DEBUG) {
Adrian Roosa98b32c2016-08-11 10:41:08 -0700944 Log.d(TAG, "reorient(): rot=" + mCurrentRotation);
Daniel Sandler60ee2562011-07-22 12:34:33 -0400945 }
Michael Jurkaa5d0ddb2012-03-09 17:41:41 -0800946
Matthew Ng5fd80412018-02-14 14:40:31 -0800947 // Resolve layout direction if not resolved since components changing layout direction such
948 // as changing languages will recreate this view and the direction will be resolved later
949 if (!isLayoutDirectionResolved()) {
950 resolveLayoutDirection();
951 }
Matthew Ngd0a73e72018-03-02 15:16:03 -0800952 updateNavButtonIcons();
Xiaohui Chen9efa5de2016-11-22 10:34:38 -0800953
Charles Chenaa94d95b2019-02-19 14:18:19 +0800954 getHomeButton().setVertical(mIsVertical);
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400955 }
Daniel Sandler48852952011-12-01 14:34:23 -0500956
Daniel Sandler0b69b592012-01-23 21:08:36 -0500957 @Override
Matthew Ngff638122019-03-21 17:17:18 -0700958 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
959 int w = MeasureSpec.getSize(widthMeasureSpec);
960 int h = MeasureSpec.getSize(heightMeasureSpec);
John Spurlockcd686b52013-06-05 10:13:46 -0400961 if (DEBUG) Log.d(TAG, String.format(
Matthew Ngff638122019-03-21 17:17:18 -0700962 "onMeasure: (%dx%d) old: (%dx%d)", w, h, getMeasuredWidth(), getMeasuredHeight()));
Daniel Sandlere03bc952012-04-27 16:11:22 -0400963
Winson Chung4723b4e2019-03-25 16:49:36 -0700964 final boolean newVertical = w > 0 && h > w
Tracy Zhou24fd0282019-05-20 14:40:38 -0700965 && !isGesturalMode(mNavBarMode);
Charles Chenaa94d95b2019-02-19 14:18:19 +0800966 if (newVertical != mIsVertical) {
967 mIsVertical = newVertical;
968 if (DEBUG) {
Matthew Ngff638122019-03-21 17:17:18 -0700969 Log.d(TAG, String.format("onMeasure: h=%d, w=%d, vert=%s", h, w,
Charles Chenaa94d95b2019-02-19 14:18:19 +0800970 mIsVertical ? "y" : "n"));
971 }
Daniel Sandlere03bc952012-04-27 16:11:22 -0400972 reorient();
Selim Cinek92d892c2014-09-11 15:11:00 +0200973 notifyVerticalChangedListener(newVertical);
Daniel Sandlere03bc952012-04-27 16:11:22 -0400974 }
Winson Chung775d2872019-03-27 14:14:01 -0700975
Tracy Zhou24fd0282019-05-20 14:40:38 -0700976 if (isGesturalMode(mNavBarMode)) {
Winson Chung775d2872019-03-27 14:14:01 -0700977 // Update the nav bar background to match the height of the visible nav bar
978 int height = mIsVertical
979 ? getResources().getDimensionPixelSize(
980 com.android.internal.R.dimen.navigation_bar_height_landscape)
981 : getResources().getDimensionPixelSize(
982 com.android.internal.R.dimen.navigation_bar_height);
983 int frameHeight = getResources().getDimensionPixelSize(
984 com.android.internal.R.dimen.navigation_bar_frame_height);
985 mBarTransitions.setBackgroundFrame(new Rect(0, frameHeight - height, w, h));
986 }
987
Matthew Ngff638122019-03-21 17:17:18 -0700988 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Daniel Sandler0b69b592012-01-23 21:08:36 -0500989 }
990
Selim Cinek92d892c2014-09-11 15:11:00 +0200991 private void notifyVerticalChangedListener(boolean newVertical) {
992 if (mOnVerticalChangedListener != null) {
993 mOnVerticalChangedListener.onVerticalChanged(newVertical);
994 }
995 }
996
Selim Cinek17a327a2014-08-25 15:03:48 +0200997 @Override
998 protected void onConfigurationChanged(Configuration newConfig) {
999 super.onConfigurationChanged(newConfig);
Matthew Ng8c056c12018-10-15 15:16:46 -07001000 mTmpLastConfiguration.updateFrom(mConfiguration);
1001 mConfiguration.updateFrom(newConfig);
1002 boolean uiCarModeChanged = updateCarMode();
Matthew Ng8c056c12018-10-15 15:16:46 -07001003 updateIcons(mTmpLastConfiguration);
Winsonfde2e6a2016-03-22 16:03:10 -07001004 updateRecentsIcon();
Matthew Ng8c056c12018-10-15 15:16:46 -07001005 mRecentsOnboarding.onConfigurationChanged(mConfiguration);
1006 if (uiCarModeChanged || mTmpLastConfiguration.densityDpi != mConfiguration.densityDpi
1007 || mTmpLastConfiguration.getLayoutDirection() != mConfiguration.getLayoutDirection()) {
Jorim Jaggi11c62e12016-04-05 20:41:21 -07001008 // If car mode or density changes, we need to reset the icons.
Matthew Ngd0a73e72018-03-02 15:16:03 -08001009 updateNavButtonIcons();
Jorim Jaggi11c62e12016-04-05 20:41:21 -07001010 }
Sriram Viswanathan9ebbe6a2015-11-16 17:59:22 -08001011 }
1012
1013 /**
1014 * If the configuration changed, update the carmode and return that it was updated.
1015 */
Matthew Ng8c056c12018-10-15 15:16:46 -07001016 private boolean updateCarMode() {
Sriram Viswanathan9ebbe6a2015-11-16 17:59:22 -08001017 boolean uiCarModeChanged = false;
Matthew Ng8c056c12018-10-15 15:16:46 -07001018 if (mConfiguration != null) {
1019 int uiMode = mConfiguration.uiMode & Configuration.UI_MODE_TYPE_MASK;
Justin Paupore01915a12016-09-28 17:41:26 -07001020 final boolean isCarMode = (uiMode == Configuration.UI_MODE_TYPE_CAR);
1021
1022 if (isCarMode != mInCarMode) {
1023 mInCarMode = isCarMode;
Justin Paupore01915a12016-09-28 17:41:26 -07001024 if (ALTERNATE_CAR_MODE_UI) {
1025 mUseCarModeUi = isCarMode;
1026 uiCarModeChanged = true;
1027 } else {
1028 // Don't use car mode behavior if ALTERNATE_CAR_MODE_UI not set.
1029 mUseCarModeUi = false;
1030 }
Sriram Viswanathan9ebbe6a2015-11-16 17:59:22 -08001031 }
1032 }
1033 return uiCarModeChanged;
Selim Cinek17a327a2014-08-25 15:03:48 +02001034 }
1035
Daniel Sandler48852952011-12-01 14:34:23 -05001036 private String getResourceName(int resId) {
1037 if (resId != 0) {
John Spurlock01534782014-01-13 11:59:22 -05001038 final android.content.res.Resources res = getContext().getResources();
Daniel Sandler48852952011-12-01 14:34:23 -05001039 try {
1040 return res.getResourceName(resId);
1041 } catch (android.content.res.Resources.NotFoundException ex) {
1042 return "(unknown)";
1043 }
1044 } else {
1045 return "(null)";
1046 }
1047 }
1048
1049 private static String visibilityToString(int vis) {
1050 switch (vis) {
1051 case View.INVISIBLE:
1052 return "INVISIBLE";
1053 case View.GONE:
1054 return "GONE";
1055 default:
1056 return "VISIBLE";
1057 }
1058 }
1059
Jason Monk67e6c802016-08-30 14:09:21 -04001060 @Override
1061 protected void onAttachedToWindow() {
1062 super.onAttachedToWindow();
Adrian Roos7e58a082018-03-09 16:40:56 +01001063 requestApplyInsets();
Siarhei Vishniakoufdb42772017-06-29 10:32:11 -07001064 reorient();
Tracy Zhouefc34662019-04-22 13:37:12 -07001065 onNavigationModeChanged(mNavBarMode);
Winson Chungf9e30272018-03-26 17:25:36 -07001066 setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
Tracy Zhoucb0362a2019-06-18 10:59:11 -07001067 if (mRotationButtonController != null) {
1068 mRotationButtonController.registerListeners();
1069 }
Matthew Ngb831fb42019-01-30 11:20:48 -08001070
Sunny Goyala6a58122019-04-02 10:20:29 -07001071 mEdgeBackGestureHandler.onNavBarAttached();
Tracy Zhouefc34662019-04-22 13:37:12 -07001072 getViewTreeObserver().addOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
Jason Monk67e6c802016-08-30 14:09:21 -04001073 }
1074
1075 @Override
1076 protected void onDetachedFromWindow() {
1077 super.onDetachedFromWindow();
Winson Chung1aa24b92019-04-24 15:17:33 -07001078 Dependency.get(NavigationModeController.class).removeListener(this);
Tony Wickhamfb63fe82018-01-16 12:14:06 -08001079 setUpSwipeUpOnboarding(false);
Matthew Ng761562d2018-09-17 11:13:21 -07001080 for (int i = 0; i < mButtonDispatchers.size(); ++i) {
1081 mButtonDispatchers.valueAt(i).onDestroy();
1082 }
Tracy Zhoucb0362a2019-06-18 10:59:11 -07001083 if (mRotationButtonController != null) {
1084 mRotationButtonController.unregisterListeners();
1085 }
1086
Sunny Goyala6a58122019-04-02 10:20:29 -07001087 mEdgeBackGestureHandler.onNavBarDetached();
Tracy Zhouefc34662019-04-22 13:37:12 -07001088 getViewTreeObserver().removeOnComputeInternalInsetsListener(
1089 mOnComputeInternalInsetsListener);
Tony Wickhamfb63fe82018-01-16 12:14:06 -08001090 }
1091
1092 private void setUpSwipeUpOnboarding(boolean connectedToOverviewProxy) {
1093 if (connectedToOverviewProxy) {
Tony Wickham05c1f852018-02-06 12:32:54 -08001094 mRecentsOnboarding.onConnectedToLauncher();
Tony Wickhamfb63fe82018-01-16 12:14:06 -08001095 } else {
Tony Wickham05c1f852018-02-06 12:32:54 -08001096 mRecentsOnboarding.onDisconnectedFromLauncher();
Tony Wickhamfb63fe82018-01-16 12:14:06 -08001097 }
Jason Monk67e6c802016-08-30 14:09:21 -04001098 }
1099
Daniel Sandler48852952011-12-01 14:34:23 -05001100 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1101 pw.println("NavigationBarView {");
1102 final Rect r = new Rect();
Jeff Browna8b9def2012-07-23 14:22:49 -07001103 final Point size = new Point();
Jeff Chang2aaa91a2018-11-08 18:04:16 +08001104 getContextDisplay().getRealSize(size);
Daniel Sandler48852952011-12-01 14:34:23 -05001105
Jason Monk2a6ea9c2017-01-26 11:14:51 -05001106 pw.println(String.format(" this: " + StatusBar.viewInfo(this)
Daniel Sandler48852952011-12-01 14:34:23 -05001107 + " " + visibilityToString(getVisibility())));
1108
1109 getWindowVisibleDisplayFrame(r);
Jeff Browna8b9def2012-07-23 14:22:49 -07001110 final boolean offscreen = r.right > size.x || r.bottom > size.y;
John Spurlock209bede2013-07-17 12:23:27 -04001111 pw.println(" window: "
Daniel Sandler48852952011-12-01 14:34:23 -05001112 + r.toShortString()
1113 + " " + visibilityToString(getWindowVisibility())
1114 + (offscreen ? " OFFSCREEN!" : ""));
1115
Winson Chung661d5f92018-05-21 18:41:39 -07001116 pw.println(String.format(" mCurrentView: id=%s (%dx%d) %s %f",
Rakesh Iyerf51fe4e2016-02-09 10:51:50 -08001117 getResourceName(getCurrentView().getId()),
1118 getCurrentView().getWidth(), getCurrentView().getHeight(),
Winson Chung661d5f92018-05-21 18:41:39 -07001119 visibilityToString(getCurrentView().getVisibility()),
1120 getCurrentView().getAlpha()));
Daniel Sandler48852952011-12-01 14:34:23 -05001121
Sunny Goyalded62f02019-05-01 14:35:49 -07001122 pw.println(String.format(" disabled=0x%08x vertical=%s darkIntensity=%.2f",
Daniel Sandler48852952011-12-01 14:34:23 -05001123 mDisabledFlags,
Charles Chenaa94d95b2019-02-19 14:18:19 +08001124 mIsVertical ? "true" : "false",
Matthew Ngeb0b0942018-10-12 16:42:11 -07001125 getLightTransitionsController().getCurrentDarkIntensity()));
Daniel Sandler48852952011-12-01 14:34:23 -05001126
John Spurlock56d007b2013-10-28 18:40:56 -04001127 dumpButton(pw, "back", getBackButton());
1128 dumpButton(pw, "home", getHomeButton());
1129 dumpButton(pw, "rcnt", getRecentsButton());
Matthew Ng25593cc2018-09-12 16:05:41 -07001130 dumpButton(pw, "rota", getRotateSuggestionButton());
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001131 dumpButton(pw, "a11y", getAccessibilityButton());
Daniel Sandler48852952011-12-01 14:34:23 -05001132
Daniel Sandler48852952011-12-01 14:34:23 -05001133 pw.println(" }");
Matthew Ng25593cc2018-09-12 16:05:41 -07001134
1135 mContextualButtonGroup.dump(pw);
1136 mRecentsOnboarding.dump(pw);
Winson Chung775d2872019-03-27 14:14:01 -07001137 mTintController.dump(pw);
Winson Chung316f6732019-06-14 09:31:46 -07001138 mEdgeBackGestureHandler.dump(pw);
Daniel Sandler48852952011-12-01 14:34:23 -05001139 }
Jim Millere898ac52012-04-06 17:10:57 -07001140
Adrian Roos7e58a082018-03-09 16:40:56 +01001141 @Override
1142 public WindowInsets onApplyWindowInsets(WindowInsets insets) {
Selim Cineke50b1212019-06-04 18:40:31 -07001143 int leftInset = insets.getSystemWindowInsetLeft();
1144 int rightInset = insets.getSystemWindowInsetRight();
1145 setPadding(leftInset, insets.getSystemWindowInsetTop(), rightInset,
1146 insets.getSystemWindowInsetBottom());
1147 // we're passing the insets onto the gesture handler since the back arrow is only
1148 // conditionally added and doesn't always get all the insets.
1149 mEdgeBackGestureHandler.setInsets(leftInset, rightInset);
Adrian Roos7e58a082018-03-09 16:40:56 +01001150 return super.onApplyWindowInsets(insets);
1151 }
1152
Jason Monka2081822016-01-18 14:41:03 -05001153 private static void dumpButton(PrintWriter pw, String caption, ButtonDispatcher button) {
John Spurlock56d007b2013-10-28 18:40:56 -04001154 pw.print(" " + caption + ": ");
1155 if (button == null) {
1156 pw.print("null");
1157 } else {
Jason Monka2081822016-01-18 14:41:03 -05001158 pw.print(visibilityToString(button.getVisibility())
John Spurlock56d007b2013-10-28 18:40:56 -04001159 + " alpha=" + button.getAlpha()
1160 );
John Spurlock56d007b2013-10-28 18:40:56 -04001161 }
1162 pw.println();
1163 }
1164
Jorim Jaggif4797922014-08-04 22:49:41 +02001165 public interface OnVerticalChangedListener {
1166 void onVerticalChanged(boolean isVertical);
1167 }
Jason Monka2081822016-01-18 14:41:03 -05001168
Matthew Ngff638122019-03-21 17:17:18 -07001169 private final Consumer<Boolean> mDockedListener = exists -> post(() -> {
Jason Monk32e3bb52017-07-27 12:35:41 -04001170 mDockedStackExists = exists;
1171 updateRecentsIcon();
1172 });
Daniel Sandler8956dbb2011-04-22 07:55:02 -04001173}