blob: b540fb49af01dece89ff176f931d06e49e3bc1ef [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 Chungc4e06202018-02-13 10:37:35 -080019import static android.view.MotionEvent.ACTION_DOWN;
Tiger Huang44c04552018-11-29 20:06:45 +080020import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID;
Matthew Ngb831fb42019-01-30 11:20:48 -080021import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
22import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
Gus Prevasab336792018-11-14 13:52:20 -050023
24import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_QUICK_SCRUB;
25import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
Winson Chungc4e06202018-02-13 10:37:35 -080026import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_BACK;
Matthew Ng472d3e42018-06-14 15:16:55 -070027import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_DEAD_ZONE;
Winson Chungc4e06202018-02-13 10:37:35 -080028import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_HOME;
29import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
Gus Prevasab336792018-11-14 13:52:20 -050030import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_OVERVIEW;
31import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_ROTATION;
Matthew Ngb55c02c2019-02-15 16:20:31 -080032import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAV_BAR_VIEWS;
Winson Chungc4e06202018-02-13 10:37:35 -080033
John Spurlock1bbd49d2012-10-19 11:09:32 -040034import android.animation.LayoutTransition;
John Spurlock56d007b2013-10-28 18:40:56 -040035import android.animation.LayoutTransition.TransitionListener;
36import android.animation.ObjectAnimator;
Matthew Ngca4592b2018-08-06 14:12:37 -070037import android.animation.PropertyValuesHolder;
John Spurlock56d007b2013-10-28 18:40:56 -040038import android.animation.TimeInterpolator;
39import android.animation.ValueAnimator;
Jorim Jaggi40db0292016-06-27 17:58:03 -070040import android.annotation.DrawableRes;
Matthew Ngb831fb42019-01-30 11:20:48 -080041import android.annotation.IntDef;
42import android.annotation.SuppressLint;
Daniel Sandler328310c2011-09-23 15:56:52 -040043import android.app.StatusBarManager;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040044import android.content.Context;
Matthew Ng63c8f342019-03-08 14:35:00 -080045import android.content.pm.ParceledListSlice;
Selim Cinek17a327a2014-08-25 15:03:48 +020046import android.content.res.Configuration;
Matthew Nga8f24262017-12-19 11:54:24 -080047import android.graphics.Canvas;
Jeff Browna8b9def2012-07-23 14:22:49 -070048import android.graphics.Point;
Daniel Sandler48852952011-12-01 14:34:23 -050049import android.graphics.Rect;
Sunny Goyalaac6c882019-02-11 11:57:58 -080050import android.graphics.Region;
51import android.graphics.Region.Op;
Matthew Ng44b14502018-05-04 11:10:14 -070052import android.os.Bundle;
Daniel Sandler0b69b592012-01-23 21:08:36 -050053import android.os.Handler;
54import android.os.Message;
Matthew Ng86a436e2018-10-26 16:00:53 -070055import android.os.RemoteException;
Matthew Ng8f25fb962018-01-16 17:17:24 -080056import android.os.SystemProperties;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040057import android.util.AttributeSet;
John Spurlockcd686b52013-06-05 10:13:46 -040058import android.util.Log;
Matthew Ng86a436e2018-10-26 16:00:53 -070059import android.util.Slog;
Jason Monka2081822016-01-18 14:41:03 -050060import android.util.SparseArray;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040061import android.view.Display;
Matthew Ngb831fb42019-01-30 11:20:48 -080062import android.view.Gravity;
Matthew Ng63c8f342019-03-08 14:35:00 -080063import android.view.IPinnedStackController;
64import android.view.IPinnedStackListener;
Daniel Sandler1d4d30a2011-04-28 12:35:29 -040065import android.view.MotionEvent;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040066import android.view.Surface;
John Spurlockde84f0e2013-06-12 12:41:00 -040067import android.view.View;
John Spurlock1bbd49d2012-10-19 11:09:32 -040068import android.view.ViewGroup;
Adrian Roos7e58a082018-03-09 16:40:56 +010069import android.view.WindowInsets;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040070import android.view.WindowManager;
Matthew Ng86a436e2018-10-26 16:00:53 -070071import android.view.WindowManagerGlobal;
Matthew Ng44b14502018-05-04 11:10:14 -070072import android.view.accessibility.AccessibilityNodeInfo;
73import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
Jason Monkf1ff2092014-04-29 16:50:53 -040074import android.view.inputmethod.InputMethodManager;
Jason Monk86bc3312016-08-16 13:17:56 -040075import android.widget.FrameLayout;
Jason Monk67e6c802016-08-30 14:09:21 -040076
Jeff Chang2aaa91a2018-11-08 18:04:16 +080077import com.android.internal.annotations.VisibleForTesting;
Jason Monkde850bb2017-02-01 19:26:30 -050078import com.android.systemui.Dependency;
Jason Monkf85fc962017-04-19 17:13:41 -040079import com.android.systemui.DockedStackExistsListener;
Matthew Ngca4592b2018-08-06 14:12:37 -070080import com.android.systemui.Interpolators;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040081import com.android.systemui.R;
Matthew Ng44b14502018-05-04 11:10:14 -070082import com.android.systemui.SysUiServiceProvider;
Matthew Ng0548fbc2019-01-11 12:24:13 -080083import com.android.systemui.assist.AssistManager;
Jason Monk67e6c802016-08-30 14:09:21 -040084import com.android.systemui.plugins.PluginListener;
Jason Monk67e6c802016-08-30 14:09:21 -040085import com.android.systemui.plugins.statusbar.phone.NavGesture;
86import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
Gus Prevasab336792018-11-14 13:52:20 -050087import com.android.systemui.recents.OverviewProxyService;
Matthew Ng44b14502018-05-04 11:10:14 -070088import com.android.systemui.recents.Recents;
Tony Wickham05c1f852018-02-06 12:32:54 -080089import com.android.systemui.recents.RecentsOnboarding;
Gus Prevasab336792018-11-14 13:52:20 -050090import com.android.systemui.shared.plugins.PluginManager;
Matthew Ng87cbf342018-02-15 12:21:18 -080091import com.android.systemui.shared.system.ActivityManagerWrapper;
Winson Chungc4e06202018-02-13 10:37:35 -080092import com.android.systemui.shared.system.NavigationBarCompat;
Matthew Ng84db1612018-04-17 16:48:21 -070093import com.android.systemui.shared.system.WindowManagerWrapper;
Matthew Ng1cf6eac2018-11-27 15:06:55 -080094import com.android.systemui.statusbar.phone.NavigationPrototypeController.GestureAction;
95import com.android.systemui.statusbar.phone.NavigationPrototypeController.OnPrototypeChangedListener;
Daniel Sandlerc26185b2012-08-29 15:49:53 -040096import com.android.systemui.statusbar.policy.DeadZone;
Jorim Jaggi40db0292016-06-27 17:58:03 -070097import com.android.systemui.statusbar.policy.KeyButtonDrawable;
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070098
John Spurlockde84f0e2013-06-12 12:41:00 -040099import java.io.FileDescriptor;
100import java.io.PrintWriter;
Matthew Ngb831fb42019-01-30 11:20:48 -0800101import java.lang.annotation.Retention;
102import java.lang.annotation.RetentionPolicy;
Jason Monk32e3bb52017-07-27 12:35:41 -0400103import java.util.function.Consumer;
John Spurlockde84f0e2013-06-12 12:41:00 -0400104
Jason Monk67e6c802016-08-30 14:09:21 -0400105public class NavigationBarView extends FrameLayout implements PluginListener<NavGesture> {
Daniel Sandler60ee2562011-07-22 12:34:33 -0400106 final static boolean DEBUG = false;
Adrian Roosa98b32c2016-08-11 10:41:08 -0700107 final static String TAG = "StatusBar/NavBarView";
Daniel Sandler60ee2562011-07-22 12:34:33 -0400108
Matthew Ngb831fb42019-01-30 11:20:48 -0800109 @Retention(RetentionPolicy.SOURCE)
110 @IntDef({WINDOW_TARGET_BOTTOM, WINDOW_TARGET_LEFT, WINDOW_TARGET_RIGHT})
111 public @interface WindowTarget{}
112 public static final int WINDOW_TARGET_BOTTOM = 0;
113 public static final int WINDOW_TARGET_LEFT = 1;
114 public static final int WINDOW_TARGET_RIGHT = 2;
115
Daniel Sandlerc3fc3222012-10-25 13:28:33 -0400116 // slippery nav bar when everything is disabled, e.g. during setup
John Spurlock7edfbca2013-09-14 11:58:55 -0400117 final static boolean SLIPPERY_WHEN_DISABLED = true;
Daniel Sandlerc3fc3222012-10-25 13:28:33 -0400118
Justin Paupore01915a12016-09-28 17:41:26 -0700119 final static boolean ALTERNATE_CAR_MODE_UI = false;
120
Daniel Sandler5c8da942011-06-28 00:29:04 -0400121 View mCurrentView = null;
Charles Chenaa94d95b2019-02-19 14:18:19 +0800122 private View mVertical;
123 private View mHorizontal;
Daniel Sandler60ee2562011-07-22 12:34:33 -0400124
Charles Chenaa94d95b2019-02-19 14:18:19 +0800125 /** Indicates that navigation bar is vertical. */
126 private boolean mIsVertical;
Adrian Roos090b7d82016-08-02 18:36:12 -0700127 private int mCurrentRotation = -1;
Daniel Sandler60ee2562011-07-22 12:34:33 -0400128
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800129 boolean mLongClickableAccessibilityButton;
Daniel Sandler6da2b762011-09-14 16:04:59 -0400130 int mDisabledFlags = 0;
Daniel Sandler328310c2011-09-23 15:56:52 -0400131 int mNavigationIconHints = 0;
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400132
Winson Chungc4e06202018-02-13 10:37:35 -0800133 private @NavigationBarCompat.HitTarget int mDownHitTarget = HIT_TARGET_NONE;
Matthew Ngb831fb42019-01-30 11:20:48 -0800134 private @WindowTarget int mWindowHitTarget = WINDOW_TARGET_BOTTOM;
Winson Chungc4e06202018-02-13 10:37:35 -0800135 private Rect mHomeButtonBounds = new Rect();
136 private Rect mBackButtonBounds = new Rect();
Matthew Ng8a8c89c2018-03-01 13:21:43 -0800137 private Rect mRecentsButtonBounds = new Rect();
Winson Chung8079af72018-05-10 11:12:55 -0700138 private Rect mRotationButtonBounds = new Rect();
Sunny Goyalaac6c882019-02-11 11:57:58 -0800139 private final Region mActiveRegion = new Region();
Winson Chungc4e06202018-02-13 10:37:35 -0800140 private int[] mTmpPosition = new int[2];
141
Matthew Ngeb5ce832018-05-15 17:50:37 -0700142 private KeyButtonDrawable mBackIcon;
Matthew Ngec5b8412018-08-22 10:45:08 -0700143 private KeyButtonDrawable mHomeDefaultIcon;
Jorim Jaggi40db0292016-06-27 17:58:03 -0700144 private KeyButtonDrawable mRecentIcon;
145 private KeyButtonDrawable mDockedIcon;
Fabrice Di Meglio18d98242013-01-17 10:57:40 -0800146
Jason Monk67e6c802016-08-30 14:09:21 -0400147 private GestureHelper mGestureHelper;
Matthew Ng603b3292018-03-30 17:15:39 -0700148 private final DeadZone mDeadZone;
Matthew Ng1e14e962018-05-03 12:51:43 -0700149 private boolean mDeadZoneConsuming = false;
John Spurlock89835dd2013-08-16 15:06:51 -0400150 private final NavigationBarTransitions mBarTransitions;
Matthew Ngdc79e5c2017-12-14 17:37:35 -0800151 private final OverviewProxyService mOverviewProxyService;
Jim Millere898ac52012-04-06 17:10:57 -0700152
Daniel Sandler0b69b592012-01-23 21:08:36 -0500153 // workaround for LayoutTransitions leaving the nav buttons in a weird state (bug 5549288)
154 final static boolean WORKAROUND_INVALID_LAYOUT = true;
155 final static int MSG_CHECK_INVALID_LAYOUT = 8686;
156
John Spurlock56d007b2013-10-28 18:40:56 -0400157 // performs manual animation in sync with layout transitions
158 private final NavTransitionListener mTransitionListener = new NavTransitionListener();
159
Jorim Jaggif4797922014-08-04 22:49:41 +0200160 private OnVerticalChangedListener mOnVerticalChangedListener;
Jorim Jaggi37c11802015-08-18 20:27:54 -0700161 private boolean mLayoutTransitionsEnabled = true;
162 private boolean mWakeAndUnlocking;
Justin Paupore01915a12016-09-28 17:41:26 -0700163 private boolean mUseCarModeUi = false;
164 private boolean mInCarMode = false;
Jorim Jaggid30d95d2016-02-17 20:27:22 -0800165 private boolean mDockedStackExists;
Jorim Jaggif4797922014-08-04 22:49:41 +0200166
Felipe Leme15f915c2016-10-31 12:47:15 -0700167 private final SparseArray<ButtonDispatcher> mButtonDispatchers = new SparseArray<>();
Matthew Ng25593cc2018-09-12 16:05:41 -0700168 private final ContextualButtonGroup mContextualButtonGroup;
Winsonfde2e6a2016-03-22 16:03:10 -0700169 private Configuration mConfiguration;
Matthew Ng8c056c12018-10-15 15:16:46 -0700170 private Configuration mTmpLastConfiguration;
Jason Monka2081822016-01-18 14:41:03 -0500171
Adrian Roosdb12b152016-07-12 15:38:55 -0700172 private NavigationBarInflaterView mNavigationInflaterView;
Tony Wickham05c1f852018-02-06 12:32:54 -0800173 private RecentsOnboarding mRecentsOnboarding;
Matthew Ng78f88d12018-01-23 12:39:55 -0800174 private NotificationPanelView mPanelView;
Adrian Roosdb12b152016-07-12 15:38:55 -0700175
Matthew Ng355fe212018-12-14 17:42:38 -0800176 private NavBarTintController mColorAdaptionController;
Matthew Ngadd4c392019-03-01 16:02:31 -0800177 private boolean mAssistantAvailable;
Matthew Ng1cf6eac2018-11-27 15:06:55 -0800178 private NavigationPrototypeController mPrototypeController;
179 private NavigationGestureAction[] mDefaultGestureMap;
Matthew Ng86a436e2018-10-26 16:00:53 -0700180 private QuickScrubAction mQuickScrubAction;
181 private QuickStepAction mQuickStepAction;
182 private NavigationBackAction mBackAction;
Matthew Ngb9c84282018-12-06 17:15:27 -0800183 private QuickSwitchAction mQuickSwitchAction;
Matthew Ng0548fbc2019-01-11 12:24:13 -0800184 private NavigationAssistantAction mAssistantAction;
Matthew Ngf8869462019-01-18 13:31:47 -0800185 private NavigationNotificationPanelAction mNotificationPanelAction;
Matthew Ng86a436e2018-10-26 16:00:53 -0700186
Matthew Ngb831fb42019-01-30 11:20:48 -0800187 private NavigationBarEdgePanel mLeftEdgePanel;
188 private NavigationBarEdgePanel mRightEdgePanel;
189
Matthew Ng20136e62018-05-30 12:20:31 -0700190 /**
191 * Helper that is responsible for showing the right toast when a disallowed activity operation
192 * occurred. In pinned mode, we show instructions on how to break out of this mode, whilst in
193 * fully locked mode we only show that unlocking is blocked.
194 */
195 private ScreenPinningNotify mScreenPinningNotify;
196
John Spurlock56d007b2013-10-28 18:40:56 -0400197 private class NavTransitionListener implements TransitionListener {
198 private boolean mBackTransitioning;
199 private boolean mHomeAppearing;
200 private long mStartDelay;
201 private long mDuration;
202 private TimeInterpolator mInterpolator;
203
204 @Override
205 public void startTransition(LayoutTransition transition, ViewGroup container,
206 View view, int transitionType) {
207 if (view.getId() == R.id.back) {
208 mBackTransitioning = true;
209 } else if (view.getId() == R.id.home && transitionType == LayoutTransition.APPEARING) {
210 mHomeAppearing = true;
211 mStartDelay = transition.getStartDelay(transitionType);
212 mDuration = transition.getDuration(transitionType);
213 mInterpolator = transition.getInterpolator(transitionType);
214 }
215 }
216
217 @Override
218 public void endTransition(LayoutTransition transition, ViewGroup container,
219 View view, int transitionType) {
220 if (view.getId() == R.id.back) {
221 mBackTransitioning = false;
222 } else if (view.getId() == R.id.home && transitionType == LayoutTransition.APPEARING) {
223 mHomeAppearing = false;
224 }
225 }
226
227 public void onBackAltCleared() {
Jason Monka2081822016-01-18 14:41:03 -0500228 ButtonDispatcher backButton = getBackButton();
Anthony Chenada13042016-01-19 16:57:20 -0800229
John Spurlock56d007b2013-10-28 18:40:56 -0400230 // When dismissing ime during unlock, force the back button to run the same appearance
231 // animation as home (if we catch this condition early enough).
Jason Monka2081822016-01-18 14:41:03 -0500232 if (!mBackTransitioning && backButton.getVisibility() == VISIBLE
233 && mHomeAppearing && getHomeButton().getAlpha() == 0) {
John Spurlock56d007b2013-10-28 18:40:56 -0400234 getBackButton().setAlpha(0);
Anthony Chenada13042016-01-19 16:57:20 -0800235 ValueAnimator a = ObjectAnimator.ofFloat(backButton, "alpha", 0, 1);
John Spurlock56d007b2013-10-28 18:40:56 -0400236 a.setStartDelay(mStartDelay);
237 a.setDuration(mDuration);
238 a.setInterpolator(mInterpolator);
239 a.start();
240 }
241 }
242 }
243
Jason Monkf1ff2092014-04-29 16:50:53 -0400244 private final OnClickListener mImeSwitcherClickListener = new OnClickListener() {
245 @Override
246 public void onClick(View view) {
lumark0b05f9e2018-11-26 15:09:06 +0800247 mContext.getSystemService(InputMethodManager.class).showInputMethodPickerFromSystem(
248 true /* showAuxiliarySubtypes */, getContext().getDisplayId());
Jason Monkf1ff2092014-04-29 16:50:53 -0400249 }
250 };
251
Matthew Ngb831fb42019-01-30 11:20:48 -0800252 private final OnTouchListener mEdgePanelTouchListener = new OnTouchListener() {
253 @SuppressLint("ClickableViewAccessibility")
254 @Override
255 public boolean onTouch(View v, MotionEvent event) {
256 if (event.getActionMasked() == ACTION_DOWN) {
257 mWindowHitTarget = v == mLeftEdgePanel ? WINDOW_TARGET_LEFT : WINDOW_TARGET_RIGHT;
258 mDownHitTarget = HIT_TARGET_NONE;
259 }
260 return mGestureHelper.onTouchEvent(event);
261 }
262 };
263
Daniel Sandler0b69b592012-01-23 21:08:36 -0500264 private class H extends Handler {
265 public void handleMessage(Message m) {
266 switch (m.what) {
267 case MSG_CHECK_INVALID_LAYOUT:
268 final String how = "" + m.obj;
269 final int w = getWidth();
270 final int h = getHeight();
Rakesh Iyer1186faa2015-12-07 16:48:46 -0800271 final int vw = getCurrentView().getWidth();
272 final int vh = getCurrentView().getHeight();
Daniel Sandler0b69b592012-01-23 21:08:36 -0500273
274 if (h != vh || w != vw) {
John Spurlockcd686b52013-06-05 10:13:46 -0400275 Log.w(TAG, String.format(
Daniel Sandler0b69b592012-01-23 21:08:36 -0500276 "*** Invalid layout in navigation bar (%s this=%dx%d cur=%dx%d)",
277 how, w, h, vw, vh));
278 if (WORKAROUND_INVALID_LAYOUT) {
279 requestLayout();
280 }
281 }
282 break;
283 }
284 }
285 }
286
Matthew Ng44b14502018-05-04 11:10:14 -0700287 private final AccessibilityDelegate mQuickStepAccessibilityDelegate
288 = new AccessibilityDelegate() {
289 private AccessibilityAction mToggleOverviewAction;
290
291 @Override
292 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
293 super.onInitializeAccessibilityNodeInfo(host, info);
294 if (mToggleOverviewAction == null) {
295 mToggleOverviewAction = new AccessibilityAction(R.id.action_toggle_overview,
296 getContext().getString(R.string.quick_step_accessibility_toggle_overview));
297 }
298 info.addAction(mToggleOverviewAction);
299 }
300
301 @Override
302 public boolean performAccessibilityAction(View host, int action, Bundle args) {
Jason Monk05dd5672018-08-09 09:38:21 -0400303 if (action == R.id.action_toggle_overview) {
304 SysUiServiceProvider.getComponent(getContext(), Recents.class)
305 .toggleRecentApps();
306 } else {
307 return super.performAccessibilityAction(host, action, args);
Matthew Ng44b14502018-05-04 11:10:14 -0700308 }
309 return true;
310 }
311 };
312
Matthew Ng1cf6eac2018-11-27 15:06:55 -0800313 private OnPrototypeChangedListener mPrototypeListener = new OnPrototypeChangedListener() {
314 @Override
315 public void onGestureRemap(int[] actions) {
316 updateNavigationGestures();
317 }
318
319 @Override
320 public void onBackButtonVisibilityChanged(boolean visible) {
Matthew Ng8a10fb52018-12-20 16:43:56 -0800321 if (!inScreenPinning()) {
322 getBackButton().setVisibility(visible ? VISIBLE : GONE);
323 }
Matthew Ng1cf6eac2018-11-27 15:06:55 -0800324 }
Matthew Ng355fe212018-12-14 17:42:38 -0800325
326 @Override
Matthew Ngb8c30bb2018-12-21 15:25:48 -0800327 public void onHomeButtonVisibilityChanged(boolean visible) {
328 getHomeButton().setVisibility(visible ? VISIBLE : GONE);
329 }
330
331 @Override
Matthew Ng355fe212018-12-14 17:42:38 -0800332 public void onColorAdaptChanged(boolean enabled) {
333 if (enabled) {
334 mColorAdaptionController.start();
335 } else {
336 mColorAdaptionController.end();
337 }
338 }
Matthew Ngb831fb42019-01-30 11:20:48 -0800339
340 @Override
341 public void onEdgeSensitivityChanged(int width, int height) {
342 if (mLeftEdgePanel != null) {
343 mLeftEdgePanel.setDimensions(width, height);
344 }
345 if (mRightEdgePanel != null) {
346 mRightEdgePanel.setDimensions(width, height);
347 }
348 }
Matthew Ngb55c02c2019-02-15 16:20:31 -0800349
350 @Override
351 public void onHomeHandleVisiblilityChanged(boolean visible) {
352 showHomeHandle(visible);
353 }
Matthew Ngadd4c392019-03-01 16:02:31 -0800354
355 @Override
356 public void onAssistantGestureEnabled(boolean enabled) {
357 updateAssistantAvailability();
358 }
Matthew Ng1cf6eac2018-11-27 15:06:55 -0800359 };
360
Matthew Ng63c8f342019-03-08 14:35:00 -0800361 private final IPinnedStackListener.Stub mImeChangedListener = new IPinnedStackListener.Stub() {
362 @Override
363 public void onListenerRegistered(IPinnedStackController controller) {
364 }
365
366 @Override
367 public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
368 post(() -> {
369 // When the ime changes visibility, resize the edge panels to not cover the ime
370 final int width = mPrototypeController.getEdgeSensitivityWidth();
371 final int height = mContext.getDisplay().getHeight() - imeHeight
372 - getResources().getDimensionPixelOffset(R.dimen.status_bar_height);
373 if (mLeftEdgePanel != null) {
374 mLeftEdgePanel.setDimensions(width, height);
375 }
376 if (mRightEdgePanel != null) {
377 mRightEdgePanel.setDimensions(width, height);
378 }
379 });
380 }
381
382 @Override
383 public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) {
384 }
385
386 @Override
387 public void onMinimizedStateChanged(boolean isMinimized) {
388 }
389
390 @Override
391 public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
392 Rect animatingBounds, boolean fromImeAdjustment, boolean fromShelfAdjustment,
393 int displayRotation) {
394 }
395
396 @Override
397 public void onActionsChanged(ParceledListSlice actions) {
398 }
399 };
400
John Spurlocke932e302013-08-12 10:16:29 -0400401 public NavigationBarView(Context context, AttributeSet attrs) {
402 super(context, attrs);
403
Charles Chenaa94d95b2019-02-19 14:18:19 +0800404 mIsVertical = false;
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800405 mLongClickableAccessibilityButton = false;
406
Matthew Ng25593cc2018-09-12 16:05:41 -0700407 // Set up the context group of buttons
408 mContextualButtonGroup = new ContextualButtonGroup(R.id.menu_container);
409 final ContextualButton menuButton = new ContextualButton(R.id.menu,
410 R.drawable.ic_sysbar_menu);
411 final ContextualButton imeSwitcherButton = new ContextualButton(R.id.ime_switcher,
412 R.drawable.ic_ime_switcher_default);
413 final RotationContextButton rotateSuggestionButton = new RotationContextButton(
Matthew Ng761562d2018-09-17 11:13:21 -0700414 R.id.rotate_suggestion, R.drawable.ic_sysbar_rotate_button, getContext(),
Matthew Ng25593cc2018-09-12 16:05:41 -0700415 R.style.RotateButtonCCWStart90);
416 final ContextualButton accessibilityButton =
417 new ContextualButton(R.id.accessibility_button,
418 R.drawable.ic_sysbar_accessibility_button);
419 mContextualButtonGroup.addButton(menuButton);
420 mContextualButtonGroup.addButton(imeSwitcherButton);
421 mContextualButtonGroup.addButton(rotateSuggestionButton);
422 mContextualButtonGroup.addButton(accessibilityButton);
423
Matthew Ngf2946542018-02-12 14:13:18 -0800424 mOverviewProxyService = Dependency.get(OverviewProxyService.class);
425 mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
426
Winsonfde2e6a2016-03-22 16:03:10 -0700427 mConfiguration = new Configuration();
Matthew Ng8c056c12018-10-15 15:16:46 -0700428 mTmpLastConfiguration = new Configuration();
Winsonfde2e6a2016-03-22 16:03:10 -0700429 mConfiguration.updateFrom(context.getResources().getConfiguration());
John Spurlocke932e302013-08-12 10:16:29 -0400430
Matthew Ng20136e62018-05-30 12:20:31 -0700431 mScreenPinningNotify = new ScreenPinningNotify(mContext);
John Spurlock7edfbca2013-09-14 11:58:55 -0400432 mBarTransitions = new NavigationBarTransitions(this);
Jason Monka2081822016-01-18 14:41:03 -0500433
Felipe Leme15f915c2016-10-31 12:47:15 -0700434 mButtonDispatchers.put(R.id.back, new ButtonDispatcher(R.id.back));
435 mButtonDispatchers.put(R.id.home, new ButtonDispatcher(R.id.home));
Matthew Ngb55c02c2019-02-15 16:20:31 -0800436 mButtonDispatchers.put(R.id.home_handle, new ButtonDispatcher(R.id.home_handle));
Matthew Ngadd4c392019-03-01 16:02:31 -0800437 mButtonDispatchers.put(R.id.assistant_handle, new ButtonDispatcher(R.id.assistant_handle));
Felipe Leme15f915c2016-10-31 12:47:15 -0700438 mButtonDispatchers.put(R.id.recent_apps, new ButtonDispatcher(R.id.recent_apps));
Matthew Ng25593cc2018-09-12 16:05:41 -0700439 mButtonDispatchers.put(R.id.menu, menuButton);
440 mButtonDispatchers.put(R.id.ime_switcher, imeSwitcherButton);
441 mButtonDispatchers.put(R.id.accessibility_button, accessibilityButton);
442 mButtonDispatchers.put(R.id.rotate_suggestion, rotateSuggestionButton);
443 mButtonDispatchers.put(R.id.menu_container, mContextualButtonGroup);
Matthew Ng603b3292018-03-30 17:15:39 -0700444 mDeadZone = new DeadZone(this);
Matthew Ng86a436e2018-10-26 16:00:53 -0700445
446 mQuickScrubAction = new QuickScrubAction(this, mOverviewProxyService);
447 mQuickStepAction = new QuickStepAction(this, mOverviewProxyService);
448 mBackAction = new NavigationBackAction(this, mOverviewProxyService);
Matthew Ngb9c84282018-12-06 17:15:27 -0800449 mQuickSwitchAction = new QuickSwitchAction(this, mOverviewProxyService);
Matthew Ng1cf6eac2018-11-27 15:06:55 -0800450 mDefaultGestureMap = new NavigationGestureAction[] {
451 mQuickStepAction, null /* swipeDownAction*/, null /* swipeLeftAction */,
Matthew Ngb9c84282018-12-06 17:15:27 -0800452 mQuickScrubAction, null /* swipeLeftEdgeAction */, null /* swipeRightEdgeAction */
Matthew Ng1cf6eac2018-11-27 15:06:55 -0800453 };
454
455 mPrototypeController = new NavigationPrototypeController(mHandler, mContext);
456 mPrototypeController.register();
457 mPrototypeController.setOnPrototypeChangedListener(mPrototypeListener);
Matthew Ng355fe212018-12-14 17:42:38 -0800458 mColorAdaptionController = new NavBarTintController(this, getLightTransitionsController());
459 }
460
461 public NavBarTintController getColorAdaptionController() {
462 return mColorAdaptionController;
John Spurlocke932e302013-08-12 10:16:29 -0400463 }
464
465 public BarTransitions getBarTransitions() {
466 return mBarTransitions;
467 }
468
Jorim Jaggi40db0292016-06-27 17:58:03 -0700469 public LightBarTransitionsController getLightTransitionsController() {
470 return mBarTransitions.getLightTransitionsController();
471 }
472
Matthew Ng0548fbc2019-01-11 12:24:13 -0800473 public void setComponents(NotificationPanelView panel, AssistManager assistManager) {
Matthew Ng78f88d12018-01-23 12:39:55 -0800474 mPanelView = panel;
Matthew Ng0548fbc2019-01-11 12:24:13 -0800475 if (mAssistantAction == null) {
476 mAssistantAction = new NavigationAssistantAction(this, mOverviewProxyService,
477 assistManager);
478 }
Matthew Ngf8869462019-01-18 13:31:47 -0800479 if (mNotificationPanelAction == null) {
480 mNotificationPanelAction = new NavigationNotificationPanelAction(this,
481 mOverviewProxyService, panel);
482 }
Winson Chung0d3815d2018-09-25 18:11:54 -0700483 if (mGestureHelper instanceof QuickStepController) {
484 ((QuickStepController) mGestureHelper).setComponents(this);
Matthew Ng1cf6eac2018-11-27 15:06:55 -0800485 updateNavigationGestures();
486 }
487 }
488
489 private void updateNavigationGestures() {
490 if (mGestureHelper instanceof QuickStepController) {
491 final int[] assignedMap = mPrototypeController.getGestureActionMap();
492 ((QuickStepController) mGestureHelper).setGestureActions(
493 getNavigationActionFromType(assignedMap[0], mDefaultGestureMap[0]),
494 getNavigationActionFromType(assignedMap[1], mDefaultGestureMap[1]),
495 getNavigationActionFromType(assignedMap[2], mDefaultGestureMap[2]),
Matthew Ngb9c84282018-12-06 17:15:27 -0800496 getNavigationActionFromType(assignedMap[3], mDefaultGestureMap[3]),
497 getNavigationActionFromType(assignedMap[4], mDefaultGestureMap[4]),
498 getNavigationActionFromType(assignedMap[5], mDefaultGestureMap[5]));
Matthew Ng1cf6eac2018-11-27 15:06:55 -0800499 }
500 }
501
502 private NavigationGestureAction getNavigationActionFromType(@GestureAction int actionType,
503 NavigationGestureAction defaultAction) {
504 switch(actionType) {
505 case NavigationPrototypeController.ACTION_QUICKSTEP:
506 return mQuickStepAction;
507 case NavigationPrototypeController.ACTION_QUICKSCRUB:
508 return mQuickScrubAction;
509 case NavigationPrototypeController.ACTION_BACK:
510 return mBackAction;
Matthew Ngb9c84282018-12-06 17:15:27 -0800511 case NavigationPrototypeController.ACTION_QUICKSWITCH:
512 return mQuickSwitchAction;
Matthew Ng0548fbc2019-01-11 12:24:13 -0800513 case NavigationPrototypeController.ACTION_ASSISTANT:
514 return mAssistantAction;
Matthew Ngf8869462019-01-18 13:31:47 -0800515 case NavigationPrototypeController.ACTION_EXPAND_NOTIFICATION:
516 return mNotificationPanelAction;
Matthew Ng0548fbc2019-01-11 12:24:13 -0800517 case NavigationPrototypeController.ACTION_NOTHING:
518 return null;
Matthew Ng1cf6eac2018-11-27 15:06:55 -0800519 default:
520 return defaultAction;
Jason Monk67e6c802016-08-30 14:09:21 -0400521 }
Jim Millere898ac52012-04-06 17:10:57 -0700522 }
523
Jorim Jaggif4797922014-08-04 22:49:41 +0200524 public void setOnVerticalChangedListener(OnVerticalChangedListener onVerticalChangedListener) {
525 mOnVerticalChangedListener = onVerticalChangedListener;
Charles Chenaa94d95b2019-02-19 14:18:19 +0800526 notifyVerticalChangedListener(mIsVertical);
Jorim Jaggif4797922014-08-04 22:49:41 +0200527 }
528
Jim Millere898ac52012-04-06 17:10:57 -0700529 @Override
530 public boolean onInterceptTouchEvent(MotionEvent event) {
Matthew Ng472d3e42018-06-14 15:16:55 -0700531 final boolean deadZoneConsumed = shouldDeadZoneConsumeTouchEvents(event);
Winson Chungc4e06202018-02-13 10:37:35 -0800532 switch (event.getActionMasked()) {
533 case ACTION_DOWN:
534 int x = (int) event.getX();
535 int y = (int) event.getY();
536 mDownHitTarget = HIT_TARGET_NONE;
Matthew Ngb831fb42019-01-30 11:20:48 -0800537 mWindowHitTarget = WINDOW_TARGET_BOTTOM;
Matthew Ng472d3e42018-06-14 15:16:55 -0700538 if (deadZoneConsumed) {
539 mDownHitTarget = HIT_TARGET_DEAD_ZONE;
540 } else if (getBackButton().isVisible() && mBackButtonBounds.contains(x, y)) {
Winson Chungc4e06202018-02-13 10:37:35 -0800541 mDownHitTarget = HIT_TARGET_BACK;
Winson Chungc6c9d402018-05-25 18:25:52 -0700542 } else if (getHomeButton().isVisible() && mHomeButtonBounds.contains(x, y)) {
Winson Chungc4e06202018-02-13 10:37:35 -0800543 mDownHitTarget = HIT_TARGET_HOME;
Winson Chungc6c9d402018-05-25 18:25:52 -0700544 } else if (getRecentsButton().isVisible() && mRecentsButtonBounds.contains(x, y)) {
Matthew Ng8a8c89c2018-03-01 13:21:43 -0800545 mDownHitTarget = HIT_TARGET_OVERVIEW;
Winson Chungc6c9d402018-05-25 18:25:52 -0700546 } else if (getRotateSuggestionButton().isVisible()
547 && mRotationButtonBounds.contains(x, y)) {
Winson Chung8079af72018-05-10 11:12:55 -0700548 mDownHitTarget = HIT_TARGET_ROTATION;
Winson Chungc4e06202018-02-13 10:37:35 -0800549 }
550 break;
551 }
Winson Chung49658842018-02-08 12:52:21 -0800552 return mGestureHelper.onInterceptTouchEvent(event);
Jim Millere898ac52012-04-06 17:10:57 -0700553 }
554
Winson Chung4faf38a2018-02-06 08:53:37 -0800555 @Override
556 public boolean onTouchEvent(MotionEvent event) {
Matthew Ng472d3e42018-06-14 15:16:55 -0700557 shouldDeadZoneConsumeTouchEvents(event);
Jason Monk297c04e2018-08-23 17:16:59 -0400558 if (mGestureHelper != null && mGestureHelper.onTouchEvent(event)) {
Winson Chung4faf38a2018-02-06 08:53:37 -0800559 return true;
560 }
Winson Chung49658842018-02-08 12:52:21 -0800561 return super.onTouchEvent(event);
Winson Chung4faf38a2018-02-06 08:53:37 -0800562 }
563
Matthew Ng1e14e962018-05-03 12:51:43 -0700564 private boolean shouldDeadZoneConsumeTouchEvents(MotionEvent event) {
565 if (mDeadZone.onTouchEvent(event) || mDeadZoneConsuming) {
566 switch (event.getActionMasked()) {
567 case MotionEvent.ACTION_DOWN:
568 // Allow gestures starting in the deadzone to be slippery
569 setSlippery(true);
570 mDeadZoneConsuming = true;
571 break;
572 case MotionEvent.ACTION_CANCEL:
573 case MotionEvent.ACTION_UP:
574 // When a gesture started in the deadzone is finished, restore slippery state
575 updateSlippery();
576 mDeadZoneConsuming = false;
577 break;
578 }
579 return true;
580 }
581 return false;
582 }
583
Winson Chungc4e06202018-02-13 10:37:35 -0800584 public @NavigationBarCompat.HitTarget int getDownHitTarget() {
585 return mDownHitTarget;
586 }
587
Matthew Ngb831fb42019-01-30 11:20:48 -0800588 public @WindowTarget int getWindowTarget() {
589 return mWindowHitTarget;
590 }
591
Xiyuan Xiaee7dd052015-05-15 09:46:27 -0700592 public void abortCurrentGesture() {
Jason Monka2081822016-01-18 14:41:03 -0500593 getHomeButton().abortCurrentGesture();
Xiyuan Xiaee7dd052015-05-15 09:46:27 -0700594 }
595
Daniel Sandler0b69b592012-01-23 21:08:36 -0500596 private H mHandler = new H();
597
John Spurlock7edfbca2013-09-14 11:58:55 -0400598 public View getCurrentView() {
599 return mCurrentView;
600 }
601
Jason Monka2081822016-01-18 14:41:03 -0500602 public ButtonDispatcher getRecentsButton() {
Felipe Leme15f915c2016-10-31 12:47:15 -0700603 return mButtonDispatchers.get(R.id.recent_apps);
Daniel Sandler5c8da942011-06-28 00:29:04 -0400604 }
605
Jason Monka2081822016-01-18 14:41:03 -0500606 public ButtonDispatcher getMenuButton() {
Felipe Leme15f915c2016-10-31 12:47:15 -0700607 return mButtonDispatchers.get(R.id.menu);
Daniel Sandler5c8da942011-06-28 00:29:04 -0400608 }
609
Jason Monka2081822016-01-18 14:41:03 -0500610 public ButtonDispatcher getBackButton() {
Felipe Leme15f915c2016-10-31 12:47:15 -0700611 return mButtonDispatchers.get(R.id.back);
Mike Lockwoode3646dd2011-09-01 12:46:28 -0400612 }
613
Jason Monka2081822016-01-18 14:41:03 -0500614 public ButtonDispatcher getHomeButton() {
Felipe Leme15f915c2016-10-31 12:47:15 -0700615 return mButtonDispatchers.get(R.id.home);
Mike Lockwoode3646dd2011-09-01 12:46:28 -0400616 }
617
Jason Monka2081822016-01-18 14:41:03 -0500618 public ButtonDispatcher getImeSwitchButton() {
Felipe Leme15f915c2016-10-31 12:47:15 -0700619 return mButtonDispatchers.get(R.id.ime_switcher);
Jason Monkf1ff2092014-04-29 16:50:53 -0400620 }
621
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800622 public ButtonDispatcher getAccessibilityButton() {
623 return mButtonDispatchers.get(R.id.accessibility_button);
624 }
625
Matthew Ng761562d2018-09-17 11:13:21 -0700626 public RotationContextButton getRotateSuggestionButton() {
627 return (RotationContextButton) mContextualButtonGroup
628 .getContextButton(R.id.rotate_suggestion);
Mike Digman7d092772018-01-11 12:10:32 -0800629 }
630
Matthew Ngb55c02c2019-02-15 16:20:31 -0800631 public ButtonDispatcher getHomeHandle() {
632 return mButtonDispatchers.get(R.id.home_handle);
633 }
634
Matthew Ngadd4c392019-03-01 16:02:31 -0800635 public ButtonDispatcher getAssistantHandle() {
636 return mButtonDispatchers.get(R.id.assistant_handle);
637 }
638
Jorim Jaggi40db0292016-06-27 17:58:03 -0700639 public SparseArray<ButtonDispatcher> getButtonDispatchers() {
640 return mButtonDispatchers;
641 }
642
Matthew Ng9c3bce52018-02-01 22:00:31 +0000643 public boolean isRecentsButtonVisible() {
644 return getRecentsButton().getVisibility() == View.VISIBLE;
645 }
646
Matthew Ng6ff33b72018-02-27 13:47:38 -0800647 public boolean isOverviewEnabled() {
648 return (mDisabledFlags & View.STATUS_BAR_DISABLE_RECENT) == 0;
649 }
650
Matthew Ng8f25fb962018-01-16 17:17:24 -0800651 public boolean isQuickStepSwipeUpEnabled() {
Matthew Ngc1a97b12018-03-28 14:02:00 -0700652 return mOverviewProxyService.shouldShowSwipeUpUI() && isOverviewEnabled();
Matthew Ng8f25fb962018-01-16 17:17:24 -0800653 }
654
655 public boolean isQuickScrubEnabled() {
656 return SystemProperties.getBoolean("persist.quickstep.scrub.enabled", true)
Winson Chungd95a2252018-04-04 17:02:29 +0000657 && mOverviewProxyService.isEnabled() && isOverviewEnabled()
Matthew Ngc1a97b12018-03-28 14:02:00 -0700658 && ((mOverviewProxyService.getInteractionFlags() & FLAG_DISABLE_QUICK_SCRUB) == 0);
Matthew Ng8f25fb962018-01-16 17:17:24 -0800659 }
660
Matthew Ngd0a73e72018-03-02 15:16:03 -0800661 private void reloadNavIcons() {
Matthew Ng8c056c12018-10-15 15:16:46 -0700662 updateIcons(Configuration.EMPTY);
Matthew Ngd0a73e72018-03-02 15:16:03 -0800663 }
664
Matthew Ng8c056c12018-10-15 15:16:46 -0700665 private void updateIcons(Configuration oldConfig) {
666 final boolean orientationChange = oldConfig.orientation != mConfiguration.orientation;
667 final boolean densityChange = oldConfig.densityDpi != mConfiguration.densityDpi;
668 final boolean dirChange = oldConfig.getLayoutDirection() != mConfiguration.getLayoutDirection();
Matthew Ngca4592b2018-08-06 14:12:37 -0700669
670 if (orientationChange || densityChange) {
Matthew Ngd6865ba2018-08-27 17:58:41 -0700671 mDockedIcon = getDrawable(R.drawable.ic_sysbar_docked);
672 mHomeDefaultIcon = getHomeDrawable();
Winsonfde2e6a2016-03-22 16:03:10 -0700673 }
Matthew Ngca4592b2018-08-06 14:12:37 -0700674 if (densityChange || dirChange) {
Matthew Ngd6865ba2018-08-27 17:58:41 -0700675 mRecentIcon = getDrawable(R.drawable.ic_sysbar_recent);
Matthew Ng25593cc2018-09-12 16:05:41 -0700676 mContextualButtonGroup.updateIcons();
Winsonfde2e6a2016-03-22 16:03:10 -0700677 }
Matthew Ngca4592b2018-08-06 14:12:37 -0700678 if (orientationChange || densityChange || dirChange) {
Matthew Ngd6865ba2018-08-27 17:58:41 -0700679 mBackIcon = getBackDrawable();
Matthew Ngca4592b2018-08-06 14:12:37 -0700680 }
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700681 }
682
Matthew Ngd6865ba2018-08-27 17:58:41 -0700683 public KeyButtonDrawable getBackDrawable() {
684 KeyButtonDrawable drawable = chooseNavigationIconDrawable(R.drawable.ic_sysbar_back,
685 R.drawable.ic_sysbar_back_quick_step);
Matthew Ngeb5ce832018-05-15 17:50:37 -0700686 orientBackButton(drawable);
687 return drawable;
Matthew Ng87cbf342018-02-15 12:21:18 -0800688 }
689
Matthew Ngd6865ba2018-08-27 17:58:41 -0700690 public KeyButtonDrawable getHomeDrawable() {
Matthew Ngeb5ce832018-05-15 17:50:37 -0700691 final boolean quickStepEnabled = mOverviewProxyService.shouldShowSwipeUpUI();
692 KeyButtonDrawable drawable = quickStepEnabled
Matthew Ngd6865ba2018-08-27 17:58:41 -0700693 ? getDrawable(R.drawable.ic_sysbar_home_quick_step)
694 : getDrawable(R.drawable.ic_sysbar_home);
Matthew Ngeb5ce832018-05-15 17:50:37 -0700695 orientHomeButton(drawable);
696 return drawable;
Matthew Ng87cbf342018-02-15 12:21:18 -0800697 }
698
Matthew Ngeb5ce832018-05-15 17:50:37 -0700699 private void orientBackButton(KeyButtonDrawable drawable) {
700 final boolean useAltBack =
Matthew Ngca4592b2018-08-06 14:12:37 -0700701 (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
Matthew Ng8c056c12018-10-15 15:16:46 -0700702 final boolean isRtl = mConfiguration.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
Matthew Ngca4592b2018-08-06 14:12:37 -0700703 float degrees = useAltBack
704 ? (isRtl ? 270 : -90)
705 : (isRtl ? 180 : 0);
706 if (drawable.getRotation() == degrees) {
707 return;
708 }
709
710 // Animate the back button's rotation to the new degrees and only in portrait move up the
711 // back button to line up with the other buttons
Charles Chenaa94d95b2019-02-19 14:18:19 +0800712 float targetY = !mOverviewProxyService.shouldShowSwipeUpUI() && !mIsVertical && useAltBack
Matthew Ngca4592b2018-08-06 14:12:37 -0700713 ? - getResources().getDimension(R.dimen.navbar_back_button_ime_offset)
714 : 0;
715 ObjectAnimator navBarAnimator = ObjectAnimator.ofPropertyValuesHolder(drawable,
716 PropertyValuesHolder.ofFloat(KeyButtonDrawable.KEY_DRAWABLE_ROTATE, degrees),
717 PropertyValuesHolder.ofFloat(KeyButtonDrawable.KEY_DRAWABLE_TRANSLATE_Y, targetY));
718 navBarAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
719 navBarAnimator.setDuration(200);
720 navBarAnimator.start();
Matthew Ng87cbf342018-02-15 12:21:18 -0800721 }
722
Matthew Ngeb5ce832018-05-15 17:50:37 -0700723 private void orientHomeButton(KeyButtonDrawable drawable) {
Charles Chenaa94d95b2019-02-19 14:18:19 +0800724 drawable.setRotation(mIsVertical ? 90 : 0);
Matthew Ngeb5ce832018-05-15 17:50:37 -0700725 }
726
Matthew Ngd6865ba2018-08-27 17:58:41 -0700727 private KeyButtonDrawable chooseNavigationIconDrawable(@DrawableRes int icon,
728 @DrawableRes int quickStepIcon) {
Matthew Ngc1a97b12018-03-28 14:02:00 -0700729 final boolean quickStepEnabled = mOverviewProxyService.shouldShowSwipeUpUI();
Matthew Ngd6865ba2018-08-27 17:58:41 -0700730 return quickStepEnabled ? getDrawable(quickStepIcon) : getDrawable(icon);
Matthew Ngeb5ce832018-05-15 17:50:37 -0700731 }
732
Matthew Ngd6865ba2018-08-27 17:58:41 -0700733 private KeyButtonDrawable getDrawable(@DrawableRes int icon) {
Matthew Ng25593cc2018-09-12 16:05:41 -0700734 return KeyButtonDrawable.create(mContext, icon, true /* hasShadow */);
Matthew Ngeb5ce832018-05-15 17:50:37 -0700735 }
736
Matthew Ngd6865ba2018-08-27 17:58:41 -0700737 private KeyButtonDrawable getDrawable(@DrawableRes int icon, boolean hasShadow) {
Matthew Ng25593cc2018-09-12 16:05:41 -0700738 return KeyButtonDrawable.create(mContext, icon, hasShadow);
Mike Digman7d092772018-01-11 12:10:32 -0800739 }
740
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700741 @Override
742 public void setLayoutDirection(int layoutDirection) {
Matthew Ngd0a73e72018-03-02 15:16:03 -0800743 reloadNavIcons();
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700744
745 super.setLayoutDirection(layoutDirection);
Daniel Sandler1d4d30a2011-04-28 12:35:29 -0400746 }
747
Matthew Ngd0a73e72018-03-02 15:16:03 -0800748 public void setNavigationIconHints(int hints) {
749 if (hints == mNavigationIconHints) return;
John Spurlock56d007b2013-10-28 18:40:56 -0400750 final boolean backAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
751 if ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0 && !backAlt) {
752 mTransitionListener.onBackAltCleared();
753 }
Daniel Sandler328310c2011-09-23 15:56:52 -0400754 if (DEBUG) {
John Spurlock01534782014-01-13 11:59:22 -0500755 android.widget.Toast.makeText(getContext(),
Daniel Sandler328310c2011-09-23 15:56:52 -0400756 "Navigation icon hints = " + hints,
757 500).show();
758 }
Daniel Sandler328310c2011-09-23 15:56:52 -0400759 mNavigationIconHints = hints;
Matthew Ngd0a73e72018-03-02 15:16:03 -0800760 updateNavButtonIcons();
761 }
Daniel Sandler328310c2011-09-23 15:56:52 -0400762
Matthew Ngd0a73e72018-03-02 15:16:03 -0800763 public void setDisabledFlags(int disabledFlags) {
764 if (mDisabledFlags == disabledFlags) return;
765
766 final boolean overviewEnabledBefore = isOverviewEnabled();
767 mDisabledFlags = disabledFlags;
768
769 // Update icons if overview was just enabled to ensure the correct icons are present
770 if (!overviewEnabledBefore && isOverviewEnabled()) {
771 reloadNavIcons();
772 }
773
774 updateNavButtonIcons();
Winson Chung1be4c7e2018-05-23 18:24:13 -0700775 updateSlippery();
Tracy Zhou98140912018-06-05 12:09:14 -0700776 setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
Matthew Ngd0a73e72018-03-02 15:16:03 -0800777 }
778
779 public void updateNavButtonIcons() {
Sriram Viswanathan9ebbe6a2015-11-16 17:59:22 -0800780 // We have to replace or restore the back and home button icons when exiting or entering
781 // carmode, respectively. Recents are not available in CarMode in nav bar so change
782 // to recent icon is not required.
Matthew Ngeb5ce832018-05-15 17:50:37 -0700783 final boolean useAltBack =
784 (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
Matthew Ngd6865ba2018-08-27 17:58:41 -0700785 KeyButtonDrawable backIcon = mBackIcon;
Matthew Ngec5b8412018-08-22 10:45:08 -0700786 orientBackButton(backIcon);
Matthew Ngd6865ba2018-08-27 17:58:41 -0700787 KeyButtonDrawable homeIcon = mHomeDefaultIcon;
Matthew Ngeb5ce832018-05-15 17:50:37 -0700788 if (!mUseCarModeUi) {
Matthew Ngeb5ce832018-05-15 17:50:37 -0700789 orientHomeButton(homeIcon);
790 }
791 getHomeButton().setImageDrawable(homeIcon);
Jason Monka2081822016-01-18 14:41:03 -0500792 getBackButton().setImageDrawable(backIcon);
Sriram Viswanathan9ebbe6a2015-11-16 17:59:22 -0800793
Jorim Jaggid30d95d2016-02-17 20:27:22 -0800794 updateRecentsIcon();
Sriram Viswanathan9ebbe6a2015-11-16 17:59:22 -0800795
Mike Digmana48cf192018-02-12 17:52:48 -0800796 // Update IME button visibility, a11y and rotate button always overrides the appearance
Matthew Ng25593cc2018-09-12 16:05:41 -0700797 mContextualButtonGroup.setButtonVisiblity(R.id.ime_switcher,
798 (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800799
Jorim Jaggi40db0292016-06-27 17:58:03 -0700800 mBarTransitions.reapplyDarkIntensity();
Daniel Sandler328310c2011-09-23 15:56:52 -0400801
Matthew Ngd0a73e72018-03-02 15:16:03 -0800802 boolean disableHome = ((mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
Sriram Viswanathan469caae2016-03-22 13:11:50 -0700803
Matthew Ng78ba6e22018-09-24 16:55:36 -0700804 // TODO(b/113914868): investigation log for disappearing home button
805 Log.i(TAG, "updateNavButtonIcons (b/113914868): home disabled=" + disableHome
806 + " mDisabledFlags=" + mDisabledFlags);
Matthew Ngb8c30bb2018-12-21 15:25:48 -0800807 disableHome |= mPrototypeController.hideHomeButton();
Matthew Ng78ba6e22018-09-24 16:55:36 -0700808
Jeff Chang2aaa91a2018-11-08 18:04:16 +0800809 // Always disable recents when alternate car mode UI is active and for secondary displays.
810 boolean disableRecent = isRecentsButtonDisabled();
Charles Hee57ff812017-10-26 10:01:35 +0100811
Matthew Ngb687c8a2018-10-02 11:31:38 -0700812 boolean disableBack = QuickStepController.shouldhideBackButton(getContext())
Matthew Ngc83b9892018-08-21 16:31:13 -0700813 || (((mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0) && !useAltBack);
Daniel Sandler029d5872011-09-12 00:58:58 -0400814
Matthew Ng87cbf342018-02-15 12:21:18 -0800815 // When screen pinning, don't hide back and home when connected service or back and
816 // recents buttons when disconnected from launcher service in screen pinning mode,
817 // as they are used for exiting.
Matthew Ng6ff33b72018-02-27 13:47:38 -0800818 final boolean pinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive();
Winson Chungd95a2252018-04-04 17:02:29 +0000819 if (mOverviewProxyService.isEnabled()) {
Matthew Ng87cbf342018-02-15 12:21:18 -0800820 // Use interaction flags to show/hide navigation buttons but will be shown if required
821 // to exit screen pinning.
Matthew Ng8f25fb962018-01-16 17:17:24 -0800822 final int flags = mOverviewProxyService.getInteractionFlags();
823 disableRecent |= (flags & FLAG_SHOW_OVERVIEW_BUTTON) == 0;
Matthew Ng6ff33b72018-02-27 13:47:38 -0800824 if (pinningActive) {
Matthew Ng87cbf342018-02-15 12:21:18 -0800825 disableBack = disableHome = false;
Matthew Ng87cbf342018-02-15 12:21:18 -0800826 }
Matthew Ng6ff33b72018-02-27 13:47:38 -0800827 } else if (pinningActive) {
Matthew Ng87cbf342018-02-15 12:21:18 -0800828 disableBack = disableRecent = false;
Matthew Ngdc79e5c2017-12-14 17:37:35 -0800829 }
Charles Hee57ff812017-10-26 10:01:35 +0100830
Rakesh Iyer1186faa2015-12-07 16:48:46 -0800831 ViewGroup navButtons = (ViewGroup) getCurrentView().findViewById(R.id.nav_buttons);
John Spurlock56d007b2013-10-28 18:40:56 -0400832 if (navButtons != null) {
833 LayoutTransition lt = navButtons.getLayoutTransition();
John Spurlock1bbd49d2012-10-19 11:09:32 -0400834 if (lt != null) {
John Spurlock56d007b2013-10-28 18:40:56 -0400835 if (!lt.getTransitionListeners().contains(mTransitionListener)) {
836 lt.addTransitionListener(mTransitionListener);
837 }
John Spurlock1bbd49d2012-10-19 11:09:32 -0400838 }
839 }
840
Jason Monka2081822016-01-18 14:41:03 -0500841 getBackButton().setVisibility(disableBack ? View.INVISIBLE : View.VISIBLE);
Jason Monk188908f2016-01-22 10:23:51 -0500842 getHomeButton().setVisibility(disableHome ? View.INVISIBLE : View.VISIBLE);
Jason Monka2081822016-01-18 14:41:03 -0500843 getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE);
John Spurlock56d007b2013-10-28 18:40:56 -0400844 }
845
Jeff Chang2aaa91a2018-11-08 18:04:16 +0800846 @VisibleForTesting
847 boolean isRecentsButtonDisabled() {
848 return mUseCarModeUi || !isOverviewEnabled()
849 || getContext().getDisplayId() != Display.DEFAULT_DISPLAY;
850 }
851
852 private Display getContextDisplay() {
853 return getContext().getDisplay();
854 }
855
Matthew Ng87cbf342018-02-15 12:21:18 -0800856 public boolean inScreenPinning() {
Matthew Ng6ff33b72018-02-27 13:47:38 -0800857 return ActivityManagerWrapper.getInstance().isScreenPinningActive();
Jason Monk17488b92014-11-06 11:26:14 -0500858 }
859
Jorim Jaggi37c11802015-08-18 20:27:54 -0700860 public void setLayoutTransitionsEnabled(boolean enabled) {
861 mLayoutTransitionsEnabled = enabled;
862 updateLayoutTransitionsEnabled();
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700863 }
864
Jorim Jaggi37c11802015-08-18 20:27:54 -0700865 public void setWakeAndUnlocking(boolean wakeAndUnlocking) {
866 setUseFadingAnimations(wakeAndUnlocking);
867 mWakeAndUnlocking = wakeAndUnlocking;
868 updateLayoutTransitionsEnabled();
869 }
870
871 private void updateLayoutTransitionsEnabled() {
872 boolean enabled = !mWakeAndUnlocking && mLayoutTransitionsEnabled;
Rakesh Iyer1186faa2015-12-07 16:48:46 -0800873 ViewGroup navButtons = (ViewGroup) getCurrentView().findViewById(R.id.nav_buttons);
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700874 LayoutTransition lt = navButtons.getLayoutTransition();
Julia Reynolds8478aba2015-07-31 09:17:20 -0400875 if (lt != null) {
876 if (enabled) {
877 lt.enableTransitionType(LayoutTransition.APPEARING);
878 lt.enableTransitionType(LayoutTransition.DISAPPEARING);
879 lt.enableTransitionType(LayoutTransition.CHANGE_APPEARING);
880 lt.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
881 } else {
882 lt.disableTransitionType(LayoutTransition.APPEARING);
883 lt.disableTransitionType(LayoutTransition.DISAPPEARING);
884 lt.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
885 lt.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
886 }
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700887 }
888 }
889
890 private void setUseFadingAnimations(boolean useFadingAnimations) {
Jason Monk49fa0162017-01-11 09:21:56 -0500891 WindowManager.LayoutParams lp = (WindowManager.LayoutParams) ((ViewGroup) getParent())
892 .getLayoutParams();
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700893 if (lp != null) {
894 boolean old = lp.windowAnimations != 0;
895 if (!old && useFadingAnimations) {
896 lp.windowAnimations = R.style.Animation_NavigationBarFadeIn;
897 } else if (old && !useFadingAnimations) {
898 lp.windowAnimations = 0;
899 } else {
900 return;
901 }
902 WindowManager wm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
Jason Monk49fa0162017-01-11 09:21:56 -0500903 wm.updateViewLayout((View) getParent(), lp);
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700904 }
905 }
906
Matthew Ng2ea93b72018-03-14 19:43:18 +0000907 public void onNavigationButtonLongPress(View v) {
Jason Monk297c04e2018-08-23 17:16:59 -0400908 if (mGestureHelper != null) {
909 mGestureHelper.onNavigationButtonLongPress(v);
910 }
Matthew Ng2ea93b72018-03-14 19:43:18 +0000911 }
912
Matthew Ng78f88d12018-01-23 12:39:55 -0800913 public void onPanelExpandedChange(boolean expanded) {
914 updateSlippery();
915 }
916
Matthew Ng8f25fb962018-01-16 17:17:24 -0800917 public void updateStates() {
Matthew Ng44b14502018-05-04 11:10:14 -0700918 final boolean showSwipeUpUI = mOverviewProxyService.shouldShowSwipeUpUI();
Mike Digmanf77fb912018-05-21 11:21:30 -0700919
920 if (mNavigationInflaterView != null) {
Matthew Ngb55c02c2019-02-15 16:20:31 -0800921 if (mPrototypeController.showHomeHandle()) {
922 showHomeHandle(true /* visible */);
923 }
924
Mike Digmanf77fb912018-05-21 11:21:30 -0700925 // Reinflate the navbar if needed, no-op unless the swipe up state changes
926 mNavigationInflaterView.onLikelyDefaultLayoutChange();
927 }
928
Matthew Ng8f25fb962018-01-16 17:17:24 -0800929 updateSlippery();
Winson Chung770d7e92018-03-20 17:51:39 -0700930 reloadNavIcons();
Matthew Ngd0a73e72018-03-02 15:16:03 -0800931 updateNavButtonIcons();
Winson Chungf9e30272018-03-26 17:25:36 -0700932 setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
Matthew Ng44b14502018-05-04 11:10:14 -0700933 WindowManagerWrapper.getInstance().setNavBarVirtualKeyHapticFeedbackEnabled(!showSwipeUpUI);
934 getHomeButton().setAccessibilityDelegate(
935 showSwipeUpUI ? mQuickStepAccessibilityDelegate : null);
Matthew Ng8f25fb962018-01-16 17:17:24 -0800936 }
937
Matthew Ng90ef0632018-08-15 13:53:15 -0700938 public boolean isNotificationsFullyCollapsed() {
939 return mPanelView.isFullyCollapsed();
940 }
941
942 /**
943 * Updates the {@link WindowManager.LayoutParams.FLAG_SLIPPERY} state dependent on if swipe up
944 * is enabled, or the notifications is fully opened without being in an animated state. If
945 * slippery is enabled, touch events will leave the nav bar window and enter into the fullscreen
946 * app/home window, if not nav bar will receive a cancelled touch event once gesture leaves bar.
947 */
Matthew Ng472d3e42018-06-14 15:16:55 -0700948 public void updateSlippery() {
Matthew Ng90ef0632018-08-15 13:53:15 -0700949 setSlippery(!isQuickStepSwipeUpEnabled() ||
950 (mPanelView.isFullyExpanded() && !mPanelView.isCollapsing()));
Matthew Ng78f88d12018-01-23 12:39:55 -0800951 }
952
Matthew Ng7d05e772017-11-09 14:41:07 -0800953 private void setSlippery(boolean slippery) {
Matthew Ngb831fb42019-01-30 11:20:48 -0800954 setWindowFlag(WindowManager.LayoutParams.FLAG_SLIPPERY, slippery);
955 }
956
957 public void setWindowTouchable(boolean flag) {
958 setWindowFlag(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, !flag);
959 if (mLeftEdgePanel != null) {
960 mLeftEdgePanel.setWindowFlag(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, !flag);
961 }
962 if (mRightEdgePanel != null) {
963 mRightEdgePanel.setWindowFlag(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, !flag);
964 }
965 }
966
967 private void setWindowFlag(int flags, boolean enable) {
Matthew Ng7d05e772017-11-09 14:41:07 -0800968 final ViewGroup navbarView = ((ViewGroup) getParent());
Matthew Ngb55c02c2019-02-15 16:20:31 -0800969 if (navbarView == null) {
970 return;
971 }
Matthew Ngb831fb42019-01-30 11:20:48 -0800972 WindowManager.LayoutParams lp = (WindowManager.LayoutParams) navbarView.getLayoutParams();
973 if (lp == null || enable == ((lp.flags & flags) != 0)) {
Matthew Ng9c3bce52018-02-01 22:00:31 +0000974 return;
975 }
Matthew Ngb831fb42019-01-30 11:20:48 -0800976 if (enable) {
977 lp.flags |= flags;
978 } else {
979 lp.flags &= ~flags;
Matthew Ng7d05e772017-11-09 14:41:07 -0800980 }
Matthew Ngb831fb42019-01-30 11:20:48 -0800981 WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
982 wm.updateViewLayout(navbarView, lp);
Matthew Ng7d05e772017-11-09 14:41:07 -0800983 }
984
Matthew Ngb55c02c2019-02-15 16:20:31 -0800985 private void showHomeHandle(boolean visible) {
986 mNavigationInflaterView.onTuningChanged(NAV_BAR_VIEWS,
987 visible ? getContext().getString(R.string.config_navBarLayoutHandle) : null);
988
989 // Color adaption is tied with showing home handle, only avaliable if visible
990 if (visible) {
991 mColorAdaptionController.start();
992 } else {
993 mColorAdaptionController.end();
994 }
995 }
996
Matthew Ngadd4c392019-03-01 16:02:31 -0800997 public void setAssistantAvailable(boolean available) {
998 mAssistantAvailable = available;
999 updateAssistantAvailability();
1000 }
1001
1002 // TODO(b/112934365): move this back to NavigationBarFragment when prototype is removed
1003 private void updateAssistantAvailability() {
1004 boolean available = mAssistantAvailable && mPrototypeController.isAssistantGestureEnabled();
1005 getAssistantHandle().setVisibility(available ? View.VISIBLE : View.GONE);
1006 if (mOverviewProxyService.getProxy() != null) {
1007 try {
1008 mOverviewProxyService.getProxy().onAssistantAvailable(available);
1009 } catch (RemoteException e) {
1010 Log.w(TAG, "Unable to send assistant availability data to launcher");
1011 }
1012 }
1013 }
1014
Daniel Sandler56598cd2011-09-15 16:02:56 -04001015 public void setMenuVisibility(final boolean show) {
Matthew Ng25593cc2018-09-12 16:05:41 -07001016 mContextualButtonGroup.setButtonVisiblity(R.id.menu, show);
Daniel Sandler56598cd2011-09-15 16:02:56 -04001017 }
1018
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001019 public void setAccessibilityButtonState(final boolean visible, final boolean longClickable) {
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001020 mLongClickableAccessibilityButton = longClickable;
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001021 getAccessibilityButton().setLongClickable(longClickable);
Matthew Ng25593cc2018-09-12 16:05:41 -07001022 mContextualButtonGroup.setButtonVisiblity(R.id.accessibility_button, visible);
Mike Digmana48cf192018-02-12 17:52:48 -08001023 }
1024
Tracy Zhou1ac592c2018-07-25 13:47:37 -07001025 void hideRecentsOnboarding() {
1026 mRecentsOnboarding.hide(true);
1027 }
1028
Jim Miller960892c2012-05-23 15:50:04 -07001029 @Override
Daniel Sandler8956dbb2011-04-22 07:55:02 -04001030 public void onFinishInflate() {
Winson Chung661d5f92018-05-21 18:41:39 -07001031 mNavigationInflaterView = findViewById(R.id.navigation_inflater);
Felipe Leme15f915c2016-10-31 12:47:15 -07001032 mNavigationInflaterView.setButtonDispatchers(mButtonDispatchers);
Jason Monka2081822016-01-18 14:41:03 -05001033
1034 getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
Selim Cinek17a327a2014-08-25 15:03:48 +02001035
Jason Monk32e3bb52017-07-27 12:35:41 -04001036 DockedStackExistsListener.register(mDockedListener);
Charles Chenaa94d95b2019-02-19 14:18:19 +08001037 updateOrientationViews();
Matthew Ng25593cc2018-09-12 16:05:41 -07001038 reloadNavIcons();
Jorim Jaggia6c934e2015-12-21 13:22:31 +01001039 }
1040
Matthew Nga8f24262017-12-19 11:54:24 -08001041 public void onDarkIntensityChange(float intensity) {
1042 if (mGestureHelper != null) {
1043 mGestureHelper.onDarkIntensityChange(intensity);
1044 }
1045 }
1046
1047 @Override
1048 protected void onDraw(Canvas canvas) {
Jason Monk297c04e2018-08-23 17:16:59 -04001049 if (mGestureHelper != null) {
1050 mGestureHelper.onDraw(canvas);
1051 }
Matthew Ng603b3292018-03-30 17:15:39 -07001052 mDeadZone.onDraw(canvas);
Matthew Nga8f24262017-12-19 11:54:24 -08001053 super.onDraw(canvas);
1054 }
1055
1056 @Override
1057 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1058 super.onLayout(changed, left, top, right, bottom);
Sunny Goyalaac6c882019-02-11 11:57:58 -08001059
1060 mActiveRegion.setEmpty();
1061 updateButtonLocation(getBackButton(), mBackButtonBounds, true);
1062 updateButtonLocation(getHomeButton(), mHomeButtonBounds, false);
1063 updateButtonLocation(getRecentsButton(), mRecentsButtonBounds, false);
1064 updateButtonLocation(getRotateSuggestionButton(), mRotationButtonBounds, true);
1065 // TODO: Handle button visibility changes
1066 mOverviewProxyService.onActiveNavBarRegionChanges(mActiveRegion);
Jason Monk297c04e2018-08-23 17:16:59 -04001067 if (mGestureHelper != null) {
1068 mGestureHelper.onLayout(changed, left, top, right, bottom);
1069 }
Tracy Zhou559d97c2018-04-07 23:54:46 -07001070 mRecentsOnboarding.setNavBarHeight(getMeasuredHeight());
Matthew Nga8f24262017-12-19 11:54:24 -08001071 }
1072
Sunny Goyalaac6c882019-02-11 11:57:58 -08001073 private void updateButtonLocation(ButtonDispatcher button, Rect buttonBounds,
1074 boolean isActive) {
Winson Chungc4e06202018-02-13 10:37:35 -08001075 View view = button.getCurrentView();
1076 if (view == null) {
1077 buttonBounds.setEmpty();
1078 return;
1079 }
Matthew Ng3b7e3902018-03-22 16:06:09 -07001080 // Temporarily reset the translation back to origin to get the position in window
1081 final float posX = view.getTranslationX();
1082 final float posY = view.getTranslationY();
1083 view.setTranslationX(0);
1084 view.setTranslationY(0);
Sunny Goyalaac6c882019-02-11 11:57:58 -08001085
1086 if (isActive) {
1087 view.getLocationOnScreen(mTmpPosition);
1088 buttonBounds.set(mTmpPosition[0], mTmpPosition[1],
1089 mTmpPosition[0] + view.getMeasuredWidth(),
1090 mTmpPosition[1] + view.getMeasuredHeight());
1091 mActiveRegion.op(buttonBounds, Op.UNION);
1092 }
Winson Chungc4e06202018-02-13 10:37:35 -08001093 view.getLocationInWindow(mTmpPosition);
1094 buttonBounds.set(mTmpPosition[0], mTmpPosition[1],
1095 mTmpPosition[0] + view.getMeasuredWidth(),
1096 mTmpPosition[1] + view.getMeasuredHeight());
Matthew Ng3b7e3902018-03-22 16:06:09 -07001097 view.setTranslationX(posX);
1098 view.setTranslationY(posY);
Winson Chungc4e06202018-02-13 10:37:35 -08001099 }
1100
Charles Chenaa94d95b2019-02-19 14:18:19 +08001101 private void updateOrientationViews() {
1102 mHorizontal = findViewById(R.id.horizontal);
1103 mVertical = findViewById(R.id.vertical);
Jason Monk9a6552d2016-05-20 11:21:59 -04001104
Jason Monk199a2d02017-07-28 11:08:27 -04001105 updateCurrentView();
Daniel Sandler8956dbb2011-04-22 07:55:02 -04001106 }
1107
Charles Chenaa94d95b2019-02-19 14:18:19 +08001108 boolean needsReorient(int rotation) {
Adrian Roosa98b32c2016-08-11 10:41:08 -07001109 return mCurrentRotation != rotation;
Adrian Roos090b7d82016-08-02 18:36:12 -07001110 }
1111
Jason Monk199a2d02017-07-28 11:08:27 -04001112 private void updateCurrentView() {
Charles Chenaa94d95b2019-02-19 14:18:19 +08001113 resetViews();
1114 mCurrentView = mIsVertical ? mVertical : mHorizontal;
Daniel Sandler5c8da942011-06-28 00:29:04 -04001115 mCurrentView.setVisibility(View.VISIBLE);
Charles Chenaa94d95b2019-02-19 14:18:19 +08001116 mNavigationInflaterView.setVertical(mIsVertical);
1117 mCurrentRotation = getContextDisplay().getRotation();
1118 mNavigationInflaterView.setAlternativeOrder(mCurrentRotation == Surface.ROTATION_90);
Matthew Ng1efc9c32018-04-11 18:13:56 -07001119 mNavigationInflaterView.updateButtonDispatchersCurrentView();
Jorim Jaggi37c11802015-08-18 20:27:54 -07001120 updateLayoutTransitionsEnabled();
Charles Chenaa94d95b2019-02-19 14:18:19 +08001121 }
1122
1123 private void resetViews() {
1124 mHorizontal.setVisibility(View.GONE);
1125 mVertical.setVisibility(View.GONE);
Jason Monk9a6552d2016-05-20 11:21:59 -04001126 }
1127
1128 private void updateRecentsIcon() {
Charles Chenaa94d95b2019-02-19 14:18:19 +08001129 mDockedIcon.setRotation(mDockedStackExists && mIsVertical ? 90 : 0);
Jason Monk9a6552d2016-05-20 11:21:59 -04001130 getRecentsButton().setImageDrawable(mDockedStackExists ? mDockedIcon : mRecentIcon);
Jorim Jaggi40db0292016-06-27 17:58:03 -07001131 mBarTransitions.reapplyDarkIntensity();
Jason Monk9a6552d2016-05-20 11:21:59 -04001132 }
1133
Matthew Ng20136e62018-05-30 12:20:31 -07001134 public void showPinningEnterExitToast(boolean entering) {
1135 if (entering) {
1136 mScreenPinningNotify.showPinningStartToast();
Matthew Ng8a10fb52018-12-20 16:43:56 -08001137
1138 // TODO(b/112934365): remove after prototype finished, only needed to escape from pin
1139 getBackButton().setVisibility(VISIBLE);
Matthew Ngb8c30bb2018-12-21 15:25:48 -08001140 getHomeButton().setVisibility(VISIBLE);
Matthew Ng20136e62018-05-30 12:20:31 -07001141 } else {
1142 mScreenPinningNotify.showPinningExitToast();
1143 }
1144 }
1145
1146 public void showPinningEscapeToast() {
1147 mScreenPinningNotify.showEscapeToast(isRecentsButtonVisible());
1148 }
1149
Jason Monk9a6552d2016-05-20 11:21:59 -04001150 public boolean isVertical() {
Charles Chenaa94d95b2019-02-19 14:18:19 +08001151 return mIsVertical;
Jason Monk9a6552d2016-05-20 11:21:59 -04001152 }
1153
1154 public void reorient() {
Jason Monk199a2d02017-07-28 11:08:27 -04001155 updateCurrentView();
Daniel Sandler8956dbb2011-04-22 07:55:02 -04001156
Siarhei Vishniakoufdb42772017-06-29 10:32:11 -07001157 ((NavigationBarFrame) getRootView()).setDeadZone(mDeadZone);
Matthew Ng603b3292018-03-30 17:15:39 -07001158 mDeadZone.onConfigurationChanged(mCurrentRotation);
Daniel Sandlerc26185b2012-08-29 15:49:53 -04001159
Daniel Sandler6da2b762011-09-14 16:04:59 -04001160 // force the low profile & disabled states into compliance
Adrian Roos8a8ffd42015-05-26 18:30:37 -07001161 mBarTransitions.init();
Daniel Sandler6da2b762011-09-14 16:04:59 -04001162
Daniel Sandler60ee2562011-07-22 12:34:33 -04001163 if (DEBUG) {
Adrian Roosa98b32c2016-08-11 10:41:08 -07001164 Log.d(TAG, "reorient(): rot=" + mCurrentRotation);
Daniel Sandler60ee2562011-07-22 12:34:33 -04001165 }
Michael Jurkaa5d0ddb2012-03-09 17:41:41 -08001166
Matthew Ng5fd80412018-02-14 14:40:31 -08001167 // Resolve layout direction if not resolved since components changing layout direction such
1168 // as changing languages will recreate this view and the direction will be resolved later
1169 if (!isLayoutDirectionResolved()) {
1170 resolveLayoutDirection();
1171 }
Selim Cinek92d892c2014-09-11 15:11:00 +02001172 updateTaskSwitchHelper();
Matthew Ngd0a73e72018-03-02 15:16:03 -08001173 updateNavButtonIcons();
Xiaohui Chen9efa5de2016-11-22 10:34:38 -08001174
Charles Chenaa94d95b2019-02-19 14:18:19 +08001175 getHomeButton().setVertical(mIsVertical);
Daniel Sandler8956dbb2011-04-22 07:55:02 -04001176 }
Daniel Sandler48852952011-12-01 14:34:23 -05001177
Selim Cinek92d892c2014-09-11 15:11:00 +02001178 private void updateTaskSwitchHelper() {
Jason Monkde850bb2017-02-01 19:26:30 -05001179 if (mGestureHelper == null) return;
Selim Cinek92d892c2014-09-11 15:11:00 +02001180 boolean isRtl = (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL);
Tiger Huang44c04552018-11-29 20:06:45 +08001181 int navBarPos = NAV_BAR_INVALID;
Matthew Ng86a436e2018-10-26 16:00:53 -07001182 try {
Tiger Huang44c04552018-11-29 20:06:45 +08001183 navBarPos = WindowManagerGlobal.getWindowManagerService().getNavBarPosition(
Jeff Chang2aaa91a2018-11-08 18:04:16 +08001184 getContext().getDisplayId());
Matthew Ng86a436e2018-10-26 16:00:53 -07001185 } catch (RemoteException e) {
1186 Slog.e(TAG, "Failed to get nav bar position.", e);
1187 }
Matthew Ngb831fb42019-01-30 11:20:48 -08001188
1189 // For landscape, hide the panel that would interfere with navigation bar layout
1190 if (mLeftEdgePanel != null && mRightEdgePanel != null) {
1191 mLeftEdgePanel.setVisibility(VISIBLE);
1192 mRightEdgePanel.setVisibility(VISIBLE);
1193 if (navBarPos == NAV_BAR_LEFT) {
1194 mLeftEdgePanel.setVisibility(GONE);
1195 } else if (navBarPos == NAV_BAR_RIGHT) {
1196 mRightEdgePanel.setVisibility(GONE);
1197 }
1198 }
Matthew Ng86a436e2018-10-26 16:00:53 -07001199 mGestureHelper.setBarState(isRtl, navBarPos);
Selim Cinek92d892c2014-09-11 15:11:00 +02001200 }
1201
Daniel Sandler0b69b592012-01-23 21:08:36 -05001202 @Override
1203 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
John Spurlockcd686b52013-06-05 10:13:46 -04001204 if (DEBUG) Log.d(TAG, String.format(
Daniel Sandler0b69b592012-01-23 21:08:36 -05001205 "onSizeChanged: (%dx%d) old: (%dx%d)", w, h, oldw, oldh));
Daniel Sandlere03bc952012-04-27 16:11:22 -04001206
1207 final boolean newVertical = w > 0 && h > w;
Charles Chenaa94d95b2019-02-19 14:18:19 +08001208 if (newVertical != mIsVertical) {
1209 mIsVertical = newVertical;
1210 if (DEBUG) {
1211 Log.d(TAG, String.format("onSizeChanged: h=%d, w=%d, vert=%s", h, w,
1212 mIsVertical ? "y" : "n"));
1213 }
Daniel Sandlere03bc952012-04-27 16:11:22 -04001214 reorient();
Selim Cinek92d892c2014-09-11 15:11:00 +02001215 notifyVerticalChangedListener(newVertical);
Daniel Sandlere03bc952012-04-27 16:11:22 -04001216 }
1217
Daniel Sandler0b69b592012-01-23 21:08:36 -05001218 postCheckForInvalidLayout("sizeChanged");
1219 super.onSizeChanged(w, h, oldw, oldh);
1220 }
1221
Selim Cinek92d892c2014-09-11 15:11:00 +02001222 private void notifyVerticalChangedListener(boolean newVertical) {
1223 if (mOnVerticalChangedListener != null) {
1224 mOnVerticalChangedListener.onVerticalChanged(newVertical);
1225 }
1226 }
1227
Selim Cinek17a327a2014-08-25 15:03:48 +02001228 @Override
1229 protected void onConfigurationChanged(Configuration newConfig) {
1230 super.onConfigurationChanged(newConfig);
Matthew Ng8c056c12018-10-15 15:16:46 -07001231 mTmpLastConfiguration.updateFrom(mConfiguration);
1232 mConfiguration.updateFrom(newConfig);
1233 boolean uiCarModeChanged = updateCarMode();
Selim Cinek92d892c2014-09-11 15:11:00 +02001234 updateTaskSwitchHelper();
Matthew Ng8c056c12018-10-15 15:16:46 -07001235 updateIcons(mTmpLastConfiguration);
Winsonfde2e6a2016-03-22 16:03:10 -07001236 updateRecentsIcon();
Matthew Ng8c056c12018-10-15 15:16:46 -07001237 mRecentsOnboarding.onConfigurationChanged(mConfiguration);
1238 if (uiCarModeChanged || mTmpLastConfiguration.densityDpi != mConfiguration.densityDpi
1239 || mTmpLastConfiguration.getLayoutDirection() != mConfiguration.getLayoutDirection()) {
Jorim Jaggi11c62e12016-04-05 20:41:21 -07001240 // If car mode or density changes, we need to reset the icons.
Matthew Ngd0a73e72018-03-02 15:16:03 -08001241 updateNavButtonIcons();
Jorim Jaggi11c62e12016-04-05 20:41:21 -07001242 }
Matthew Ngb55c02c2019-02-15 16:20:31 -08001243
1244 if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
1245 mColorAdaptionController.start();
1246 } else {
1247 mColorAdaptionController.end();
1248 }
Sriram Viswanathan9ebbe6a2015-11-16 17:59:22 -08001249 }
1250
1251 /**
1252 * If the configuration changed, update the carmode and return that it was updated.
1253 */
Matthew Ng8c056c12018-10-15 15:16:46 -07001254 private boolean updateCarMode() {
Sriram Viswanathan9ebbe6a2015-11-16 17:59:22 -08001255 boolean uiCarModeChanged = false;
Matthew Ng8c056c12018-10-15 15:16:46 -07001256 if (mConfiguration != null) {
1257 int uiMode = mConfiguration.uiMode & Configuration.UI_MODE_TYPE_MASK;
Justin Paupore01915a12016-09-28 17:41:26 -07001258 final boolean isCarMode = (uiMode == Configuration.UI_MODE_TYPE_CAR);
1259
1260 if (isCarMode != mInCarMode) {
1261 mInCarMode = isCarMode;
Justin Paupore01915a12016-09-28 17:41:26 -07001262 if (ALTERNATE_CAR_MODE_UI) {
1263 mUseCarModeUi = isCarMode;
1264 uiCarModeChanged = true;
1265 } else {
1266 // Don't use car mode behavior if ALTERNATE_CAR_MODE_UI not set.
1267 mUseCarModeUi = false;
1268 }
Sriram Viswanathan9ebbe6a2015-11-16 17:59:22 -08001269 }
1270 }
1271 return uiCarModeChanged;
Selim Cinek17a327a2014-08-25 15:03:48 +02001272 }
1273
Daniel Sandler0b69b592012-01-23 21:08:36 -05001274 /*
1275 @Override
1276 protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
John Spurlockcd686b52013-06-05 10:13:46 -04001277 if (DEBUG) Log.d(TAG, String.format(
John Spurlock209bede2013-07-17 12:23:27 -04001278 "onLayout: %s (%d,%d,%d,%d)",
Daniel Sandler0b69b592012-01-23 21:08:36 -05001279 changed?"changed":"notchanged", left, top, right, bottom));
1280 super.onLayout(changed, left, top, right, bottom);
1281 }
1282
1283 // uncomment this for extra defensiveness in WORKAROUND_INVALID_LAYOUT situations: if all else
1284 // fails, any touch on the display will fix the layout.
1285 @Override
1286 public boolean onInterceptTouchEvent(MotionEvent ev) {
John Spurlockcd686b52013-06-05 10:13:46 -04001287 if (DEBUG) Log.d(TAG, "onInterceptTouchEvent: " + ev.toString());
Daniel Sandler0b69b592012-01-23 21:08:36 -05001288 if (ev.getAction() == MotionEvent.ACTION_DOWN) {
1289 postCheckForInvalidLayout("touch");
1290 }
1291 return super.onInterceptTouchEvent(ev);
1292 }
1293 */
John Spurlock209bede2013-07-17 12:23:27 -04001294
Daniel Sandler0b69b592012-01-23 21:08:36 -05001295
Daniel Sandler48852952011-12-01 14:34:23 -05001296 private String getResourceName(int resId) {
1297 if (resId != 0) {
John Spurlock01534782014-01-13 11:59:22 -05001298 final android.content.res.Resources res = getContext().getResources();
Daniel Sandler48852952011-12-01 14:34:23 -05001299 try {
1300 return res.getResourceName(resId);
1301 } catch (android.content.res.Resources.NotFoundException ex) {
1302 return "(unknown)";
1303 }
1304 } else {
1305 return "(null)";
1306 }
1307 }
1308
Daniel Sandler0b69b592012-01-23 21:08:36 -05001309 private void postCheckForInvalidLayout(final String how) {
1310 mHandler.obtainMessage(MSG_CHECK_INVALID_LAYOUT, 0, 0, how).sendToTarget();
1311 }
1312
Daniel Sandler48852952011-12-01 14:34:23 -05001313 private static String visibilityToString(int vis) {
1314 switch (vis) {
1315 case View.INVISIBLE:
1316 return "INVISIBLE";
1317 case View.GONE:
1318 return "GONE";
1319 default:
1320 return "VISIBLE";
1321 }
1322 }
1323
Jason Monk67e6c802016-08-30 14:09:21 -04001324 @Override
1325 protected void onAttachedToWindow() {
1326 super.onAttachedToWindow();
Adrian Roos7e58a082018-03-09 16:40:56 +01001327 requestApplyInsets();
Siarhei Vishniakoufdb42772017-06-29 10:32:11 -07001328 reorient();
Jason Monkde850bb2017-02-01 19:26:30 -05001329 onPluginDisconnected(null); // Create default gesture helper
Jason Monk5bec68f2017-02-08 20:45:10 -08001330 Dependency.get(PluginManager.class).addPluginListener(this,
1331 NavGesture.class, false /* Only one */);
Winson Chungf9e30272018-03-26 17:25:36 -07001332 setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
Matthew Ng355fe212018-12-14 17:42:38 -08001333 mColorAdaptionController.start();
Matthew Ngb831fb42019-01-30 11:20:48 -08001334
1335 if (mPrototypeController.isEnabled()) {
1336 WindowManager wm = (WindowManager) getContext()
1337 .getSystemService(Context.WINDOW_SERVICE);
1338 int width = mPrototypeController.getEdgeSensitivityWidth();
1339 int height = mPrototypeController.getEdgeSensitivityHeight();
Zak Cohen8d8d6772019-02-07 16:50:24 -08001340 // Explicitly left and right, not start and end as this is device relative.
Matthew Ngb831fb42019-01-30 11:20:48 -08001341 mLeftEdgePanel = NavigationBarEdgePanel.create(getContext(), width, height,
Matthew Ng63c8f342019-03-08 14:35:00 -08001342 Gravity.LEFT | Gravity.TOP);
Matthew Ngb831fb42019-01-30 11:20:48 -08001343 mRightEdgePanel = NavigationBarEdgePanel.create(getContext(), width, height,
Matthew Ng63c8f342019-03-08 14:35:00 -08001344 Gravity.RIGHT | Gravity.TOP);
Matthew Ngb831fb42019-01-30 11:20:48 -08001345 mLeftEdgePanel.setOnTouchListener(mEdgePanelTouchListener);
1346 mRightEdgePanel.setOnTouchListener(mEdgePanelTouchListener);
1347 wm.addView(mLeftEdgePanel, mLeftEdgePanel.getLayoutParams());
1348 wm.addView(mRightEdgePanel, mRightEdgePanel.getLayoutParams());
Matthew Ng63c8f342019-03-08 14:35:00 -08001349
1350 try {
1351 WindowManagerWrapper.getInstance().addPinnedStackListener(mImeChangedListener);
1352 } catch (RemoteException e) {
1353 Log.e(TAG, "Failed to register pinned stack listener", e);
1354 }
Matthew Ngb831fb42019-01-30 11:20:48 -08001355 }
Jason Monk67e6c802016-08-30 14:09:21 -04001356 }
1357
1358 @Override
1359 protected void onDetachedFromWindow() {
1360 super.onDetachedFromWindow();
Jason Monkde850bb2017-02-01 19:26:30 -05001361 Dependency.get(PluginManager.class).removePluginListener(this);
1362 if (mGestureHelper != null) {
1363 mGestureHelper.destroy();
1364 }
Matthew Ng1cf6eac2018-11-27 15:06:55 -08001365 mPrototypeController.unregister();
Matthew Ng355fe212018-12-14 17:42:38 -08001366 mColorAdaptionController.stop();
Tony Wickhamfb63fe82018-01-16 12:14:06 -08001367 setUpSwipeUpOnboarding(false);
Matthew Ng761562d2018-09-17 11:13:21 -07001368 for (int i = 0; i < mButtonDispatchers.size(); ++i) {
1369 mButtonDispatchers.valueAt(i).onDestroy();
1370 }
Matthew Ngb831fb42019-01-30 11:20:48 -08001371
Matthew Ng33fa2752019-02-14 12:12:50 -08001372 WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
1373 if (mLeftEdgePanel != null) {
1374 wm.removeView(mLeftEdgePanel);
1375 }
1376 if (mRightEdgePanel != null) {
1377 wm.removeView(mRightEdgePanel);
Matthew Ngb831fb42019-01-30 11:20:48 -08001378 }
Matthew Ng63c8f342019-03-08 14:35:00 -08001379 WindowManagerWrapper.getInstance().removePinnedStackListener(mImeChangedListener);
Tony Wickhamfb63fe82018-01-16 12:14:06 -08001380 }
1381
1382 private void setUpSwipeUpOnboarding(boolean connectedToOverviewProxy) {
1383 if (connectedToOverviewProxy) {
Tony Wickham05c1f852018-02-06 12:32:54 -08001384 mRecentsOnboarding.onConnectedToLauncher();
Tony Wickhamfb63fe82018-01-16 12:14:06 -08001385 } else {
Tony Wickham05c1f852018-02-06 12:32:54 -08001386 mRecentsOnboarding.onDisconnectedFromLauncher();
Tony Wickhamfb63fe82018-01-16 12:14:06 -08001387 }
Jason Monk67e6c802016-08-30 14:09:21 -04001388 }
1389
1390 @Override
Jason Monk20ff3f92017-01-09 15:13:23 -05001391 public void onPluginConnected(NavGesture plugin, Context context) {
Jason Monk67e6c802016-08-30 14:09:21 -04001392 mGestureHelper = plugin.getGestureHelper();
1393 updateTaskSwitchHelper();
1394 }
1395
1396 @Override
1397 public void onPluginDisconnected(NavGesture plugin) {
Winson Chung0d3815d2018-09-25 18:11:54 -07001398 QuickStepController defaultHelper = new QuickStepController(getContext());
Winson Chung67f5c8b2018-09-24 12:09:19 -07001399 defaultHelper.setComponents(this);
Jason Monkde850bb2017-02-01 19:26:30 -05001400 if (mGestureHelper != null) {
1401 mGestureHelper.destroy();
1402 }
Jason Monk67e6c802016-08-30 14:09:21 -04001403 mGestureHelper = defaultHelper;
1404 updateTaskSwitchHelper();
1405 }
1406
Daniel Sandler48852952011-12-01 14:34:23 -05001407 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1408 pw.println("NavigationBarView {");
1409 final Rect r = new Rect();
Jeff Browna8b9def2012-07-23 14:22:49 -07001410 final Point size = new Point();
Jeff Chang2aaa91a2018-11-08 18:04:16 +08001411 getContextDisplay().getRealSize(size);
Daniel Sandler48852952011-12-01 14:34:23 -05001412
Jason Monk2a6ea9c2017-01-26 11:14:51 -05001413 pw.println(String.format(" this: " + StatusBar.viewInfo(this)
Daniel Sandler48852952011-12-01 14:34:23 -05001414 + " " + visibilityToString(getVisibility())));
1415
1416 getWindowVisibleDisplayFrame(r);
Jeff Browna8b9def2012-07-23 14:22:49 -07001417 final boolean offscreen = r.right > size.x || r.bottom > size.y;
John Spurlock209bede2013-07-17 12:23:27 -04001418 pw.println(" window: "
Daniel Sandler48852952011-12-01 14:34:23 -05001419 + r.toShortString()
1420 + " " + visibilityToString(getWindowVisibility())
1421 + (offscreen ? " OFFSCREEN!" : ""));
1422
Winson Chung661d5f92018-05-21 18:41:39 -07001423 pw.println(String.format(" mCurrentView: id=%s (%dx%d) %s %f",
Rakesh Iyerf51fe4e2016-02-09 10:51:50 -08001424 getResourceName(getCurrentView().getId()),
1425 getCurrentView().getWidth(), getCurrentView().getHeight(),
Winson Chung661d5f92018-05-21 18:41:39 -07001426 visibilityToString(getCurrentView().getVisibility()),
1427 getCurrentView().getAlpha()));
Daniel Sandler48852952011-12-01 14:34:23 -05001428
Matthew Ngeb0b0942018-10-12 16:42:11 -07001429 pw.println(String.format(" disabled=0x%08x vertical=%s menu=%s darkIntensity=%.2f",
Daniel Sandler48852952011-12-01 14:34:23 -05001430 mDisabledFlags,
Charles Chenaa94d95b2019-02-19 14:18:19 +08001431 mIsVertical ? "true" : "false",
Matthew Ngeb0b0942018-10-12 16:42:11 -07001432 getMenuButton().isVisible() ? "true" : "false",
1433 getLightTransitionsController().getCurrentDarkIntensity()));
Daniel Sandler48852952011-12-01 14:34:23 -05001434
John Spurlock56d007b2013-10-28 18:40:56 -04001435 dumpButton(pw, "back", getBackButton());
1436 dumpButton(pw, "home", getHomeButton());
1437 dumpButton(pw, "rcnt", getRecentsButton());
1438 dumpButton(pw, "menu", getMenuButton());
Matthew Ng25593cc2018-09-12 16:05:41 -07001439 dumpButton(pw, "rota", getRotateSuggestionButton());
Casey Burkhardt048c2bc2016-12-08 16:09:20 -08001440 dumpButton(pw, "a11y", getAccessibilityButton());
Daniel Sandler48852952011-12-01 14:34:23 -05001441
Daniel Sandler48852952011-12-01 14:34:23 -05001442 pw.println(" }");
Matthew Ng25593cc2018-09-12 16:05:41 -07001443
1444 mContextualButtonGroup.dump(pw);
Jason Monk297c04e2018-08-23 17:16:59 -04001445 if (mGestureHelper != null) {
Matthew Ng86a436e2018-10-26 16:00:53 -07001446 pw.println("Navigation Gesture Actions {");
1447 pw.print(" "); pw.println("QuickScrub Enabled=" + mQuickScrubAction.isEnabled());
1448 pw.print(" "); pw.println("QuickScrub Active=" + mQuickScrubAction.isActive());
1449 pw.print(" "); pw.println("QuickStep Enabled=" + mQuickStepAction.isEnabled());
1450 pw.print(" "); pw.println("QuickStep Active=" + mQuickStepAction.isActive());
1451 pw.print(" "); pw.println("Back Gesture Enabled=" + mBackAction.isEnabled());
1452 pw.print(" "); pw.println("Back Gesture Active=" + mBackAction.isActive());
1453 pw.println("}");
Jason Monk297c04e2018-08-23 17:16:59 -04001454 mGestureHelper.dump(pw);
1455 }
Matthew Ng25593cc2018-09-12 16:05:41 -07001456 mRecentsOnboarding.dump(pw);
Daniel Sandler48852952011-12-01 14:34:23 -05001457 }
Jim Millere898ac52012-04-06 17:10:57 -07001458
Adrian Roos7e58a082018-03-09 16:40:56 +01001459 @Override
1460 public WindowInsets onApplyWindowInsets(WindowInsets insets) {
1461 setPadding(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(),
1462 insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom());
1463 return super.onApplyWindowInsets(insets);
1464 }
1465
Jason Monka2081822016-01-18 14:41:03 -05001466 private static void dumpButton(PrintWriter pw, String caption, ButtonDispatcher button) {
John Spurlock56d007b2013-10-28 18:40:56 -04001467 pw.print(" " + caption + ": ");
1468 if (button == null) {
1469 pw.print("null");
1470 } else {
Jason Monka2081822016-01-18 14:41:03 -05001471 pw.print(visibilityToString(button.getVisibility())
John Spurlock56d007b2013-10-28 18:40:56 -04001472 + " alpha=" + button.getAlpha()
1473 );
John Spurlock56d007b2013-10-28 18:40:56 -04001474 }
1475 pw.println();
1476 }
1477
Jorim Jaggif4797922014-08-04 22:49:41 +02001478 public interface OnVerticalChangedListener {
1479 void onVerticalChanged(boolean isVertical);
1480 }
Jason Monka2081822016-01-18 14:41:03 -05001481
Jason Monk32e3bb52017-07-27 12:35:41 -04001482 private final Consumer<Boolean> mDockedListener = exists -> mHandler.post(() -> {
1483 mDockedStackExists = exists;
1484 updateRecentsIcon();
1485 });
Daniel Sandler8956dbb2011-04-22 07:55:02 -04001486}