blob: cddb1fc3a6ad2c4a238b9cf51f536e7d0b4e406b [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
John Spurlock1bbd49d2012-10-19 11:09:32 -040019import android.animation.LayoutTransition;
John Spurlock56d007b2013-10-28 18:40:56 -040020import android.animation.LayoutTransition.TransitionListener;
21import android.animation.ObjectAnimator;
22import android.animation.TimeInterpolator;
23import android.animation.ValueAnimator;
Jason Monk17488b92014-11-06 11:26:14 -050024import android.app.ActivityManagerNative;
Daniel Sandler328310c2011-09-23 15:56:52 -040025import android.app.StatusBarManager;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040026import android.content.Context;
Selim Cinek17a327a2014-08-25 15:03:48 +020027import android.content.res.Configuration;
Daniel Sandler60ee2562011-07-22 12:34:33 -040028import android.content.res.Resources;
Jeff Browna8b9def2012-07-23 14:22:49 -070029import android.graphics.Point;
Daniel Sandler48852952011-12-01 14:34:23 -050030import android.graphics.Rect;
Daniel Sandler2c9ae752012-04-27 00:14:54 -040031import android.graphics.drawable.Drawable;
Daniel Sandler0b69b592012-01-23 21:08:36 -050032import android.os.Handler;
33import android.os.Message;
Jason Monk17488b92014-11-06 11:26:14 -050034import android.os.RemoteException;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040035import android.util.AttributeSet;
John Spurlockcd686b52013-06-05 10:13:46 -040036import android.util.Log;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040037import android.view.Display;
Jorim Jaggica8c6262014-10-27 16:53:18 +010038import android.view.Gravity;
Daniel Sandler1d4d30a2011-04-28 12:35:29 -040039import android.view.MotionEvent;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040040import android.view.Surface;
John Spurlockde84f0e2013-06-12 12:41:00 -040041import android.view.View;
John Spurlock1bbd49d2012-10-19 11:09:32 -040042import android.view.ViewGroup;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040043import android.view.WindowManager;
Jason Monkf1ff2092014-04-29 16:50:53 -040044import android.view.inputmethod.InputMethodManager;
Jorim Jaggica8c6262014-10-27 16:53:18 +010045import android.widget.FrameLayout;
Daniel Sandler328310c2011-09-23 15:56:52 -040046import android.widget.ImageView;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040047import android.widget.LinearLayout;
Jason Monk17488b92014-11-06 11:26:14 -050048
Daniel Sandler8956dbb2011-04-22 07:55:02 -040049import com.android.systemui.R;
Jorim Jaggidd98d412015-11-18 15:57:38 -080050import com.android.systemui.RecentsComponent;
51import com.android.systemui.stackdivider.Divider;
Daniel Sandlerc26185b2012-08-29 15:49:53 -040052import com.android.systemui.statusbar.policy.DeadZone;
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070053import com.android.systemui.statusbar.policy.KeyButtonView;
54
John Spurlockde84f0e2013-06-12 12:41:00 -040055import java.io.FileDescriptor;
56import java.io.PrintWriter;
Selim Cinek17a327a2014-08-25 15:03:48 +020057import java.util.ArrayList;
John Spurlockde84f0e2013-06-12 12:41:00 -040058
Daniel Sandler8956dbb2011-04-22 07:55:02 -040059public class NavigationBarView extends LinearLayout {
Daniel Sandler60ee2562011-07-22 12:34:33 -040060 final static boolean DEBUG = false;
Daniel Sandler6da2b762011-09-14 16:04:59 -040061 final static String TAG = "PhoneStatusBar/NavigationBarView";
Daniel Sandler60ee2562011-07-22 12:34:33 -040062
Daniel Sandlerc3fc3222012-10-25 13:28:33 -040063 // slippery nav bar when everything is disabled, e.g. during setup
John Spurlock7edfbca2013-09-14 11:58:55 -040064 final static boolean SLIPPERY_WHEN_DISABLED = true;
Daniel Sandlerc3fc3222012-10-25 13:28:33 -040065
Daniel Sandler8956dbb2011-04-22 07:55:02 -040066 final Display mDisplay;
Daniel Sandler5c8da942011-06-28 00:29:04 -040067 View mCurrentView = null;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040068 View[] mRotatedViews = new View[4];
Daniel Sandler60ee2562011-07-22 12:34:33 -040069
70 int mBarSize;
71 boolean mVertical;
John Spurlock1bbd49d2012-10-19 11:09:32 -040072 boolean mScreenOn;
Daniel Sandler60ee2562011-07-22 12:34:33 -040073
John Spurlock7edfbca2013-09-14 11:58:55 -040074 boolean mShowMenu;
Daniel Sandler6da2b762011-09-14 16:04:59 -040075 int mDisabledFlags = 0;
Daniel Sandler328310c2011-09-23 15:56:52 -040076 int mNavigationIconHints = 0;
Daniel Sandler8956dbb2011-04-22 07:55:02 -040077
Daniel Sandler2c9ae752012-04-27 00:14:54 -040078 private Drawable mBackIcon, mBackLandIcon, mBackAltIcon, mBackAltLandIcon;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -070079 private Drawable mRecentIcon;
Fabrice Di Meglio18d98242013-01-17 10:57:40 -080080 private Drawable mRecentLandIcon;
81
Jorim Jaggidd98d412015-11-18 15:57:38 -080082 private NavigationBarGestureHelper mGestureHelper;
Daniel Sandlerc26185b2012-08-29 15:49:53 -040083 private DeadZone mDeadZone;
John Spurlock89835dd2013-08-16 15:06:51 -040084 private final NavigationBarTransitions mBarTransitions;
Jim Millere898ac52012-04-06 17:10:57 -070085
Daniel Sandler0b69b592012-01-23 21:08:36 -050086 // workaround for LayoutTransitions leaving the nav buttons in a weird state (bug 5549288)
87 final static boolean WORKAROUND_INVALID_LAYOUT = true;
88 final static int MSG_CHECK_INVALID_LAYOUT = 8686;
89
John Spurlock56d007b2013-10-28 18:40:56 -040090 // performs manual animation in sync with layout transitions
91 private final NavTransitionListener mTransitionListener = new NavTransitionListener();
92
Jorim Jaggif4797922014-08-04 22:49:41 +020093 private OnVerticalChangedListener mOnVerticalChangedListener;
Selim Cinek74c92d62014-09-01 23:53:43 +020094 private boolean mIsLayoutRtl;
Jorim Jaggi37c11802015-08-18 20:27:54 -070095 private boolean mLayoutTransitionsEnabled = true;
96 private boolean mWakeAndUnlocking;
Jorim Jaggif4797922014-08-04 22:49:41 +020097
John Spurlock56d007b2013-10-28 18:40:56 -040098 private class NavTransitionListener implements TransitionListener {
99 private boolean mBackTransitioning;
100 private boolean mHomeAppearing;
101 private long mStartDelay;
102 private long mDuration;
103 private TimeInterpolator mInterpolator;
104
105 @Override
106 public void startTransition(LayoutTransition transition, ViewGroup container,
107 View view, int transitionType) {
108 if (view.getId() == R.id.back) {
109 mBackTransitioning = true;
110 } else if (view.getId() == R.id.home && transitionType == LayoutTransition.APPEARING) {
111 mHomeAppearing = true;
112 mStartDelay = transition.getStartDelay(transitionType);
113 mDuration = transition.getDuration(transitionType);
114 mInterpolator = transition.getInterpolator(transitionType);
115 }
116 }
117
118 @Override
119 public void endTransition(LayoutTransition transition, ViewGroup container,
120 View view, int transitionType) {
121 if (view.getId() == R.id.back) {
122 mBackTransitioning = false;
123 } else if (view.getId() == R.id.home && transitionType == LayoutTransition.APPEARING) {
124 mHomeAppearing = false;
125 }
126 }
127
128 public void onBackAltCleared() {
129 // When dismissing ime during unlock, force the back button to run the same appearance
130 // animation as home (if we catch this condition early enough).
131 if (!mBackTransitioning && getBackButton().getVisibility() == VISIBLE
132 && mHomeAppearing && getHomeButton().getAlpha() == 0) {
133 getBackButton().setAlpha(0);
134 ValueAnimator a = ObjectAnimator.ofFloat(getBackButton(), "alpha", 0, 1);
135 a.setStartDelay(mStartDelay);
136 a.setDuration(mDuration);
137 a.setInterpolator(mInterpolator);
138 a.start();
139 }
140 }
141 }
142
Jason Monkf1ff2092014-04-29 16:50:53 -0400143 private final OnClickListener mImeSwitcherClickListener = new OnClickListener() {
144 @Override
145 public void onClick(View view) {
Yohei Yukawa777ef952015-11-25 20:32:24 -0800146 mContext.getSystemService(InputMethodManager.class)
Seigo Nonaka14e13912015-05-06 21:04:13 -0700147 .showInputMethodPicker(true /* showAuxiliarySubtypes */);
Jason Monkf1ff2092014-04-29 16:50:53 -0400148 }
149 };
150
Daniel Sandler0b69b592012-01-23 21:08:36 -0500151 private class H extends Handler {
152 public void handleMessage(Message m) {
153 switch (m.what) {
154 case MSG_CHECK_INVALID_LAYOUT:
155 final String how = "" + m.obj;
156 final int w = getWidth();
157 final int h = getHeight();
158 final int vw = mCurrentView.getWidth();
159 final int vh = mCurrentView.getHeight();
160
161 if (h != vh || w != vw) {
John Spurlockcd686b52013-06-05 10:13:46 -0400162 Log.w(TAG, String.format(
Daniel Sandler0b69b592012-01-23 21:08:36 -0500163 "*** Invalid layout in navigation bar (%s this=%dx%d cur=%dx%d)",
164 how, w, h, vw, vh));
165 if (WORKAROUND_INVALID_LAYOUT) {
166 requestLayout();
167 }
168 }
169 break;
170 }
171 }
172 }
173
John Spurlocke932e302013-08-12 10:16:29 -0400174 public NavigationBarView(Context context, AttributeSet attrs) {
175 super(context, attrs);
176
John Spurlocke932e302013-08-12 10:16:29 -0400177 mDisplay = ((WindowManager)context.getSystemService(
178 Context.WINDOW_SERVICE)).getDefaultDisplay();
John Spurlocke932e302013-08-12 10:16:29 -0400179
John Spurlock01534782014-01-13 11:59:22 -0500180 final Resources res = getContext().getResources();
John Spurlocke932e302013-08-12 10:16:29 -0400181 mBarSize = res.getDimensionPixelSize(R.dimen.navigation_bar_size);
182 mVertical = false;
183 mShowMenu = false;
Jorim Jaggidd98d412015-11-18 15:57:38 -0800184 mGestureHelper = new NavigationBarGestureHelper(context);
John Spurlocke932e302013-08-12 10:16:29 -0400185
186 getIcons(res);
187
John Spurlock7edfbca2013-09-14 11:58:55 -0400188 mBarTransitions = new NavigationBarTransitions(this);
John Spurlocke932e302013-08-12 10:16:29 -0400189 }
190
191 public BarTransitions getBarTransitions() {
192 return mBarTransitions;
193 }
194
Jorim Jaggidd98d412015-11-18 15:57:38 -0800195 public void setComponents(RecentsComponent recentsComponent, Divider divider) {
196 mGestureHelper.setComponents(recentsComponent, divider);
Jim Millere898ac52012-04-06 17:10:57 -0700197 }
198
Jorim Jaggif4797922014-08-04 22:49:41 +0200199 public void setOnVerticalChangedListener(OnVerticalChangedListener onVerticalChangedListener) {
200 mOnVerticalChangedListener = onVerticalChangedListener;
Selim Cinek92d892c2014-09-11 15:11:00 +0200201 notifyVerticalChangedListener(mVertical);
Jorim Jaggif4797922014-08-04 22:49:41 +0200202 }
203
Jim Millere898ac52012-04-06 17:10:57 -0700204 @Override
Jim Miller960892c2012-05-23 15:50:04 -0700205 public boolean onTouchEvent(MotionEvent event) {
Jorim Jaggidd98d412015-11-18 15:57:38 -0800206 if (mGestureHelper.onTouchEvent(event)) {
Winson Chungb1f74992014-08-08 12:53:09 -0700207 return true;
208 }
Daniel Sandlerc26185b2012-08-29 15:49:53 -0400209 if (mDeadZone != null && event.getAction() == MotionEvent.ACTION_OUTSIDE) {
210 mDeadZone.poke(event);
Jim Miller960892c2012-05-23 15:50:04 -0700211 }
Daniel Sandlerc26185b2012-08-29 15:49:53 -0400212 return super.onTouchEvent(event);
Jim Miller960892c2012-05-23 15:50:04 -0700213 }
214
215 @Override
Jim Millere898ac52012-04-06 17:10:57 -0700216 public boolean onInterceptTouchEvent(MotionEvent event) {
Jorim Jaggidd98d412015-11-18 15:57:38 -0800217 return mGestureHelper.onInterceptTouchEvent(event);
Jim Millere898ac52012-04-06 17:10:57 -0700218 }
219
Xiyuan Xiaee7dd052015-05-15 09:46:27 -0700220 public void abortCurrentGesture() {
Xiyuan Xiaee7dd052015-05-15 09:46:27 -0700221 getHomeButton().abortCurrentGesture();
222 }
223
Daniel Sandler0b69b592012-01-23 21:08:36 -0500224 private H mHandler = new H();
225
John Spurlock7edfbca2013-09-14 11:58:55 -0400226 public View getCurrentView() {
227 return mCurrentView;
228 }
229
Daniel Sandler5c8da942011-06-28 00:29:04 -0400230 public View getRecentsButton() {
231 return mCurrentView.findViewById(R.id.recent_apps);
232 }
233
234 public View getMenuButton() {
235 return mCurrentView.findViewById(R.id.menu);
236 }
237
Mike Lockwoode3646dd2011-09-01 12:46:28 -0400238 public View getBackButton() {
239 return mCurrentView.findViewById(R.id.back);
240 }
241
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700242 public KeyButtonView getHomeButton() {
243 return (KeyButtonView) mCurrentView.findViewById(R.id.home);
Mike Lockwoode3646dd2011-09-01 12:46:28 -0400244 }
245
Jason Monkf1ff2092014-04-29 16:50:53 -0400246 public View getImeSwitchButton() {
247 return mCurrentView.findViewById(R.id.ime_switcher);
248 }
249
James Cook968403d2015-07-08 15:10:33 -0700250 public View getAppShelf() {
251 return mCurrentView.findViewById(R.id.app_shelf);
252 }
253
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700254 private void getIcons(Resources res) {
Daniel Sandler2c9ae752012-04-27 00:14:54 -0400255 mBackIcon = res.getDrawable(R.drawable.ic_sysbar_back);
Dan Sandlerc263a082015-09-03 10:51:57 -0400256 mBackLandIcon = mBackIcon;
Daniel Sandler2c9ae752012-04-27 00:14:54 -0400257 mBackAltIcon = res.getDrawable(R.drawable.ic_sysbar_back_ime);
Dan Sandlerc263a082015-09-03 10:51:57 -0400258 mBackAltLandIcon = mBackAltIcon;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700259 mRecentIcon = res.getDrawable(R.drawable.ic_sysbar_recent);
Dan Sandlerc263a082015-09-03 10:51:57 -0400260 mRecentLandIcon = mRecentIcon;
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700261 }
262
263 @Override
264 public void setLayoutDirection(int layoutDirection) {
John Spurlock01534782014-01-13 11:59:22 -0500265 getIcons(getContext().getResources());
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700266
267 super.setLayoutDirection(layoutDirection);
Daniel Sandler1d4d30a2011-04-28 12:35:29 -0400268 }
269
John Spurlock1bbd49d2012-10-19 11:09:32 -0400270 public void notifyScreenOn(boolean screenOn) {
271 mScreenOn = screenOn;
272 setDisabledFlags(mDisabledFlags, true);
273 }
274
Daniel Sandler328310c2011-09-23 15:56:52 -0400275 public void setNavigationIconHints(int hints) {
276 setNavigationIconHints(hints, false);
277 }
278
279 public void setNavigationIconHints(int hints, boolean force) {
280 if (!force && hints == mNavigationIconHints) return;
John Spurlock56d007b2013-10-28 18:40:56 -0400281 final boolean backAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
282 if ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0 && !backAlt) {
283 mTransitionListener.onBackAltCleared();
284 }
Daniel Sandler328310c2011-09-23 15:56:52 -0400285 if (DEBUG) {
John Spurlock01534782014-01-13 11:59:22 -0500286 android.widget.Toast.makeText(getContext(),
Daniel Sandler328310c2011-09-23 15:56:52 -0400287 "Navigation icon hints = " + hints,
288 500).show();
289 }
290
291 mNavigationIconHints = hints;
292
John Spurlock56d007b2013-10-28 18:40:56 -0400293 ((ImageView)getBackButton()).setImageDrawable(backAlt
Daniel Sandler2c9ae752012-04-27 00:14:54 -0400294 ? (mVertical ? mBackAltLandIcon : mBackAltIcon)
295 : (mVertical ? mBackLandIcon : mBackIcon));
John Spurlocka9b46822012-11-02 10:42:39 -0400296
Fabrice Di Meglio18d98242013-01-17 10:57:40 -0800297 ((ImageView)getRecentsButton()).setImageDrawable(mVertical ? mRecentLandIcon : mRecentIcon);
Fabrice Di Meglio8afcd142012-07-27 18:27:11 -0700298
Jason Monkf1ff2092014-04-29 16:50:53 -0400299 final boolean showImeButton = ((hints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
300 getImeSwitchButton().setVisibility(showImeButton ? View.VISIBLE : View.INVISIBLE);
301 // Update menu button in case the IME state has changed.
302 setMenuVisibility(mShowMenu, true);
303
304
John Spurlocka9b46822012-11-02 10:42:39 -0400305 setDisabledFlags(mDisabledFlags, true);
Daniel Sandler328310c2011-09-23 15:56:52 -0400306 }
307
Daniel Sandler6da2b762011-09-14 16:04:59 -0400308 public void setDisabledFlags(int disabledFlags) {
Daniel Sandler6da2b762011-09-14 16:04:59 -0400309 setDisabledFlags(disabledFlags, false);
310 }
311
312 public void setDisabledFlags(int disabledFlags, boolean force) {
313 if (!force && mDisabledFlags == disabledFlags) return;
314
315 mDisabledFlags = disabledFlags;
316
Daniel Sandlerdba93562011-10-06 16:39:58 -0400317 final boolean disableHome = ((disabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
Jason Monk17488b92014-11-06 11:26:14 -0500318 boolean disableRecent = ((disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
John Spurlocka9b46822012-11-02 10:42:39 -0400319 final boolean disableBack = ((disabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0)
320 && ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) == 0);
Daniel Sandlerd5483c32012-10-19 16:44:15 -0400321 final boolean disableSearch = ((disabledFlags & View.STATUS_BAR_DISABLE_SEARCH) != 0);
Daniel Sandler029d5872011-09-12 00:58:58 -0400322
Daniel Sandlerc3fc3222012-10-25 13:28:33 -0400323 if (SLIPPERY_WHEN_DISABLED) {
324 setSlippery(disableHome && disableRecent && disableBack && disableSearch);
325 }
John Spurlockd5ef5462012-06-13 11:19:51 -0400326
John Spurlock56d007b2013-10-28 18:40:56 -0400327 ViewGroup navButtons = (ViewGroup) mCurrentView.findViewById(R.id.nav_buttons);
328 if (navButtons != null) {
329 LayoutTransition lt = navButtons.getLayoutTransition();
John Spurlock1bbd49d2012-10-19 11:09:32 -0400330 if (lt != null) {
John Spurlock56d007b2013-10-28 18:40:56 -0400331 if (!lt.getTransitionListeners().contains(mTransitionListener)) {
332 lt.addTransitionListener(mTransitionListener);
333 }
John Spurlock1bbd49d2012-10-19 11:09:32 -0400334 }
335 }
Jason Monk17488b92014-11-06 11:26:14 -0500336 if (inLockTask() && disableRecent && !disableHome) {
337 // Don't hide recents when in lock task, it is used for exiting.
338 // Unless home is hidden, then in DPM locked mode and no exit available.
339 disableRecent = false;
340 }
John Spurlock1bbd49d2012-10-19 11:09:32 -0400341
Daniel Sandler029d5872011-09-12 00:58:58 -0400342 getBackButton() .setVisibility(disableBack ? View.INVISIBLE : View.VISIBLE);
Daniel Sandlerdba93562011-10-06 16:39:58 -0400343 getHomeButton() .setVisibility(disableHome ? View.INVISIBLE : View.VISIBLE);
344 getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE);
James Cook968403d2015-07-08 15:10:33 -0700345
346 // The app shelf, if it exists, follows the visibility of the home button.
347 View appShelf = getAppShelf();
348 if (appShelf != null) {
349 appShelf.setVisibility(disableHome ? View.INVISIBLE : View.VISIBLE);
350 }
John Spurlock56d007b2013-10-28 18:40:56 -0400351 }
352
Jason Monk17488b92014-11-06 11:26:14 -0500353 private boolean inLockTask() {
354 try {
355 return ActivityManagerNative.getDefault().isInLockTaskMode();
356 } catch (RemoteException e) {
357 return false;
358 }
359 }
360
John Spurlock56d007b2013-10-28 18:40:56 -0400361 private void setVisibleOrGone(View view, boolean visible) {
362 if (view != null) {
363 view.setVisibility(visible ? VISIBLE : GONE);
Jim Millercaf24fc2013-09-10 18:37:01 -0700364 }
365 }
366
Jorim Jaggi37c11802015-08-18 20:27:54 -0700367 public void setLayoutTransitionsEnabled(boolean enabled) {
368 mLayoutTransitionsEnabled = enabled;
369 updateLayoutTransitionsEnabled();
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700370 }
371
Jorim Jaggi37c11802015-08-18 20:27:54 -0700372 public void setWakeAndUnlocking(boolean wakeAndUnlocking) {
373 setUseFadingAnimations(wakeAndUnlocking);
374 mWakeAndUnlocking = wakeAndUnlocking;
375 updateLayoutTransitionsEnabled();
376 }
377
378 private void updateLayoutTransitionsEnabled() {
379 boolean enabled = !mWakeAndUnlocking && mLayoutTransitionsEnabled;
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700380 ViewGroup navButtons = (ViewGroup) mCurrentView.findViewById(R.id.nav_buttons);
381 LayoutTransition lt = navButtons.getLayoutTransition();
Julia Reynolds8478aba2015-07-31 09:17:20 -0400382 if (lt != null) {
383 if (enabled) {
384 lt.enableTransitionType(LayoutTransition.APPEARING);
385 lt.enableTransitionType(LayoutTransition.DISAPPEARING);
386 lt.enableTransitionType(LayoutTransition.CHANGE_APPEARING);
387 lt.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
388 } else {
389 lt.disableTransitionType(LayoutTransition.APPEARING);
390 lt.disableTransitionType(LayoutTransition.DISAPPEARING);
391 lt.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
392 lt.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
393 }
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700394 }
395 }
396
397 private void setUseFadingAnimations(boolean useFadingAnimations) {
398 WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams();
399 if (lp != null) {
400 boolean old = lp.windowAnimations != 0;
401 if (!old && useFadingAnimations) {
402 lp.windowAnimations = R.style.Animation_NavigationBarFadeIn;
403 } else if (old && !useFadingAnimations) {
404 lp.windowAnimations = 0;
405 } else {
406 return;
407 }
408 WindowManager wm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
409 wm.updateViewLayout(this, lp);
410 }
411 }
412
John Spurlockd5ef5462012-06-13 11:19:51 -0400413 public void setSlippery(boolean newSlippery) {
414 WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams();
415 if (lp != null) {
416 boolean oldSlippery = (lp.flags & WindowManager.LayoutParams.FLAG_SLIPPERY) != 0;
417 if (!oldSlippery && newSlippery) {
418 lp.flags |= WindowManager.LayoutParams.FLAG_SLIPPERY;
419 } else if (oldSlippery && !newSlippery) {
420 lp.flags &= ~WindowManager.LayoutParams.FLAG_SLIPPERY;
421 } else {
422 return;
423 }
Jeff Brown98365d72012-08-19 20:30:52 -0700424 WindowManager wm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
425 wm.updateViewLayout(this, lp);
John Spurlockd5ef5462012-06-13 11:19:51 -0400426 }
427 }
428
Daniel Sandler56598cd2011-09-15 16:02:56 -0400429 public void setMenuVisibility(final boolean show) {
430 setMenuVisibility(show, false);
431 }
432
433 public void setMenuVisibility(final boolean show, final boolean force) {
434 if (!force && mShowMenu == show) return;
435
436 mShowMenu = show;
437
Jason Monkf1ff2092014-04-29 16:50:53 -0400438 // Only show Menu if IME switcher not shown.
439 final boolean shouldShow = mShowMenu &&
440 ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) == 0);
441 getMenuButton().setVisibility(shouldShow ? View.VISIBLE : View.INVISIBLE);
Daniel Sandler029d5872011-09-12 00:58:58 -0400442 }
443
Jim Miller960892c2012-05-23 15:50:04 -0700444 @Override
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400445 public void onFinishInflate() {
John Spurlock209bede2013-07-17 12:23:27 -0400446 mRotatedViews[Surface.ROTATION_0] =
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400447 mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);
448
449 mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot90);
John Spurlock209bede2013-07-17 12:23:27 -0400450
Selim Cinek17a327a2014-08-25 15:03:48 +0200451 mRotatedViews[Surface.ROTATION_270] = mRotatedViews[Surface.ROTATION_90];
Daniel Sandler5c8da942011-06-28 00:29:04 -0400452
453 mCurrentView = mRotatedViews[Surface.ROTATION_0];
Jim Millercaf24fc2013-09-10 18:37:01 -0700454
Jason Monkf1ff2092014-04-29 16:50:53 -0400455 getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
Selim Cinek17a327a2014-08-25 15:03:48 +0200456
Selim Cinek74c92d62014-09-01 23:53:43 +0200457 updateRTLOrder();
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400458 }
459
John Spurlockdcf4f212013-05-21 17:19:53 -0400460 public boolean isVertical() {
461 return mVertical;
462 }
463
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400464 public void reorient() {
465 final int rot = mDisplay.getRotation();
466 for (int i=0; i<4; i++) {
467 mRotatedViews[i].setVisibility(View.GONE);
468 }
Daniel Sandler5c8da942011-06-28 00:29:04 -0400469 mCurrentView = mRotatedViews[rot];
470 mCurrentView.setVisibility(View.VISIBLE);
Jorim Jaggi37c11802015-08-18 20:27:54 -0700471 updateLayoutTransitionsEnabled();
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400472
Jason Monkf1ff2092014-04-29 16:50:53 -0400473 getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
474
Daniel Sandlerc26185b2012-08-29 15:49:53 -0400475 mDeadZone = (DeadZone) mCurrentView.findViewById(R.id.deadzone);
476
Daniel Sandler6da2b762011-09-14 16:04:59 -0400477 // force the low profile & disabled states into compliance
Adrian Roos8a8ffd42015-05-26 18:30:37 -0700478 mBarTransitions.init();
Daniel Sandler6da2b762011-09-14 16:04:59 -0400479 setDisabledFlags(mDisabledFlags, true /* force */);
Daniel Sandler56598cd2011-09-15 16:02:56 -0400480 setMenuVisibility(mShowMenu, true /* force */);
Daniel Sandler6da2b762011-09-14 16:04:59 -0400481
Daniel Sandler60ee2562011-07-22 12:34:33 -0400482 if (DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400483 Log.d(TAG, "reorient(): rot=" + mDisplay.getRotation());
Daniel Sandler60ee2562011-07-22 12:34:33 -0400484 }
Michael Jurkaa5d0ddb2012-03-09 17:41:41 -0800485
Selim Cinek92d892c2014-09-11 15:11:00 +0200486 updateTaskSwitchHelper();
Michael Jurkaa5d0ddb2012-03-09 17:41:41 -0800487 setNavigationIconHints(mNavigationIconHints, true);
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400488 }
Daniel Sandler48852952011-12-01 14:34:23 -0500489
Selim Cinek92d892c2014-09-11 15:11:00 +0200490 private void updateTaskSwitchHelper() {
491 boolean isRtl = (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL);
Jorim Jaggidd98d412015-11-18 15:57:38 -0800492 mGestureHelper.setBarState(mVertical, isRtl);
Selim Cinek92d892c2014-09-11 15:11:00 +0200493 }
494
Daniel Sandler0b69b592012-01-23 21:08:36 -0500495 @Override
496 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
John Spurlockcd686b52013-06-05 10:13:46 -0400497 if (DEBUG) Log.d(TAG, String.format(
Daniel Sandler0b69b592012-01-23 21:08:36 -0500498 "onSizeChanged: (%dx%d) old: (%dx%d)", w, h, oldw, oldh));
Daniel Sandlere03bc952012-04-27 16:11:22 -0400499
500 final boolean newVertical = w > 0 && h > w;
501 if (newVertical != mVertical) {
502 mVertical = newVertical;
John Spurlockcd686b52013-06-05 10:13:46 -0400503 //Log.v(TAG, String.format("onSizeChanged: h=%d, w=%d, vert=%s", h, w, mVertical?"y":"n"));
Daniel Sandlere03bc952012-04-27 16:11:22 -0400504 reorient();
Selim Cinek92d892c2014-09-11 15:11:00 +0200505 notifyVerticalChangedListener(newVertical);
Daniel Sandlere03bc952012-04-27 16:11:22 -0400506 }
507
Daniel Sandler0b69b592012-01-23 21:08:36 -0500508 postCheckForInvalidLayout("sizeChanged");
509 super.onSizeChanged(w, h, oldw, oldh);
510 }
511
Selim Cinek92d892c2014-09-11 15:11:00 +0200512 private void notifyVerticalChangedListener(boolean newVertical) {
513 if (mOnVerticalChangedListener != null) {
514 mOnVerticalChangedListener.onVerticalChanged(newVertical);
515 }
516 }
517
Selim Cinek17a327a2014-08-25 15:03:48 +0200518 @Override
519 protected void onConfigurationChanged(Configuration newConfig) {
520 super.onConfigurationChanged(newConfig);
Selim Cinek74c92d62014-09-01 23:53:43 +0200521 updateRTLOrder();
Selim Cinek92d892c2014-09-11 15:11:00 +0200522 updateTaskSwitchHelper();
Selim Cinek17a327a2014-08-25 15:03:48 +0200523 }
524
525 /**
526 * In landscape, the LinearLayout is not auto mirrored since it is vertical. Therefore we
527 * have to do it manually
528 */
Selim Cinek74c92d62014-09-01 23:53:43 +0200529 private void updateRTLOrder() {
530 boolean isLayoutRtl = getResources().getConfiguration()
Selim Cinek17a327a2014-08-25 15:03:48 +0200531 .getLayoutDirection() == LAYOUT_DIRECTION_RTL;
Selim Cinek74c92d62014-09-01 23:53:43 +0200532 if (mIsLayoutRtl != isLayoutRtl) {
Selim Cinek17a327a2014-08-25 15:03:48 +0200533
534 // We swap all children of the 90 and 270 degree layouts, since they are vertical
535 View rotation90 = mRotatedViews[Surface.ROTATION_90];
536 swapChildrenOrderIfVertical(rotation90.findViewById(R.id.nav_buttons));
Jorim Jaggica8c6262014-10-27 16:53:18 +0100537 adjustExtraKeyGravity(rotation90, isLayoutRtl);
Selim Cinek17a327a2014-08-25 15:03:48 +0200538
539 View rotation270 = mRotatedViews[Surface.ROTATION_270];
540 if (rotation90 != rotation270) {
541 swapChildrenOrderIfVertical(rotation270.findViewById(R.id.nav_buttons));
Jorim Jaggica8c6262014-10-27 16:53:18 +0100542 adjustExtraKeyGravity(rotation270, isLayoutRtl);
Selim Cinek17a327a2014-08-25 15:03:48 +0200543 }
Selim Cinek74c92d62014-09-01 23:53:43 +0200544 mIsLayoutRtl = isLayoutRtl;
Selim Cinek17a327a2014-08-25 15:03:48 +0200545 }
546 }
547
Jorim Jaggica8c6262014-10-27 16:53:18 +0100548 private void adjustExtraKeyGravity(View navBar, boolean isLayoutRtl) {
549 View menu = navBar.findViewById(R.id.menu);
550 View imeSwitcher = navBar.findViewById(R.id.ime_switcher);
551 if (menu != null) {
552 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) menu.getLayoutParams();
553 lp.gravity = isLayoutRtl ? Gravity.BOTTOM : Gravity.TOP;
554 menu.setLayoutParams(lp);
555 }
556 if (imeSwitcher != null) {
557 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) imeSwitcher.getLayoutParams();
558 lp.gravity = isLayoutRtl ? Gravity.BOTTOM : Gravity.TOP;
559 imeSwitcher.setLayoutParams(lp);
560 }
561 }
Selim Cinek17a327a2014-08-25 15:03:48 +0200562
563 /**
564 * Swaps the children order of a LinearLayout if it's orientation is Vertical
565 *
566 * @param group The LinearLayout to swap the children from.
567 */
568 private void swapChildrenOrderIfVertical(View group) {
569 if (group instanceof LinearLayout) {
570 LinearLayout linearLayout = (LinearLayout) group;
571 if (linearLayout.getOrientation() == VERTICAL) {
572 int childCount = linearLayout.getChildCount();
573 ArrayList<View> childList = new ArrayList<>(childCount);
574 for (int i = 0; i < childCount; i++) {
575 childList.add(linearLayout.getChildAt(i));
576 }
577 linearLayout.removeAllViews();
578 for (int i = childCount - 1; i >= 0; i--) {
579 linearLayout.addView(childList.get(i));
580 }
581 }
582 }
583 }
584
Daniel Sandler0b69b592012-01-23 21:08:36 -0500585 /*
586 @Override
587 protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
John Spurlockcd686b52013-06-05 10:13:46 -0400588 if (DEBUG) Log.d(TAG, String.format(
John Spurlock209bede2013-07-17 12:23:27 -0400589 "onLayout: %s (%d,%d,%d,%d)",
Daniel Sandler0b69b592012-01-23 21:08:36 -0500590 changed?"changed":"notchanged", left, top, right, bottom));
591 super.onLayout(changed, left, top, right, bottom);
592 }
593
594 // uncomment this for extra defensiveness in WORKAROUND_INVALID_LAYOUT situations: if all else
595 // fails, any touch on the display will fix the layout.
596 @Override
597 public boolean onInterceptTouchEvent(MotionEvent ev) {
John Spurlockcd686b52013-06-05 10:13:46 -0400598 if (DEBUG) Log.d(TAG, "onInterceptTouchEvent: " + ev.toString());
Daniel Sandler0b69b592012-01-23 21:08:36 -0500599 if (ev.getAction() == MotionEvent.ACTION_DOWN) {
600 postCheckForInvalidLayout("touch");
601 }
602 return super.onInterceptTouchEvent(ev);
603 }
604 */
John Spurlock209bede2013-07-17 12:23:27 -0400605
Daniel Sandler0b69b592012-01-23 21:08:36 -0500606
Daniel Sandler48852952011-12-01 14:34:23 -0500607 private String getResourceName(int resId) {
608 if (resId != 0) {
John Spurlock01534782014-01-13 11:59:22 -0500609 final android.content.res.Resources res = getContext().getResources();
Daniel Sandler48852952011-12-01 14:34:23 -0500610 try {
611 return res.getResourceName(resId);
612 } catch (android.content.res.Resources.NotFoundException ex) {
613 return "(unknown)";
614 }
615 } else {
616 return "(null)";
617 }
618 }
619
Daniel Sandler0b69b592012-01-23 21:08:36 -0500620 private void postCheckForInvalidLayout(final String how) {
621 mHandler.obtainMessage(MSG_CHECK_INVALID_LAYOUT, 0, 0, how).sendToTarget();
622 }
623
Daniel Sandler48852952011-12-01 14:34:23 -0500624 private static String visibilityToString(int vis) {
625 switch (vis) {
626 case View.INVISIBLE:
627 return "INVISIBLE";
628 case View.GONE:
629 return "GONE";
630 default:
631 return "VISIBLE";
632 }
633 }
634
635 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
636 pw.println("NavigationBarView {");
637 final Rect r = new Rect();
Jeff Browna8b9def2012-07-23 14:22:49 -0700638 final Point size = new Point();
639 mDisplay.getRealSize(size);
Daniel Sandler48852952011-12-01 14:34:23 -0500640
641 pw.println(String.format(" this: " + PhoneStatusBar.viewInfo(this)
642 + " " + visibilityToString(getVisibility())));
643
644 getWindowVisibleDisplayFrame(r);
Jeff Browna8b9def2012-07-23 14:22:49 -0700645 final boolean offscreen = r.right > size.x || r.bottom > size.y;
John Spurlock209bede2013-07-17 12:23:27 -0400646 pw.println(" window: "
Daniel Sandler48852952011-12-01 14:34:23 -0500647 + r.toShortString()
648 + " " + visibilityToString(getWindowVisibility())
649 + (offscreen ? " OFFSCREEN!" : ""));
650
651 pw.println(String.format(" mCurrentView: id=%s (%dx%d) %s",
652 getResourceName(mCurrentView.getId()),
653 mCurrentView.getWidth(), mCurrentView.getHeight(),
654 visibilityToString(mCurrentView.getVisibility())));
655
John Spurlock41c1e352013-09-16 13:57:13 -0400656 pw.println(String.format(" disabled=0x%08x vertical=%s menu=%s",
Daniel Sandler48852952011-12-01 14:34:23 -0500657 mDisabledFlags,
658 mVertical ? "true" : "false",
Daniel Sandler48852952011-12-01 14:34:23 -0500659 mShowMenu ? "true" : "false"));
660
John Spurlock56d007b2013-10-28 18:40:56 -0400661 dumpButton(pw, "back", getBackButton());
662 dumpButton(pw, "home", getHomeButton());
663 dumpButton(pw, "rcnt", getRecentsButton());
664 dumpButton(pw, "menu", getMenuButton());
Daniel Sandler48852952011-12-01 14:34:23 -0500665
Daniel Sandler48852952011-12-01 14:34:23 -0500666 pw.println(" }");
667 }
Jim Millere898ac52012-04-06 17:10:57 -0700668
John Spurlock56d007b2013-10-28 18:40:56 -0400669 private static void dumpButton(PrintWriter pw, String caption, View button) {
670 pw.print(" " + caption + ": ");
671 if (button == null) {
672 pw.print("null");
673 } else {
674 pw.print(PhoneStatusBar.viewInfo(button)
675 + " " + visibilityToString(button.getVisibility())
676 + " alpha=" + button.getAlpha()
677 );
John Spurlock56d007b2013-10-28 18:40:56 -0400678 }
679 pw.println();
680 }
681
Jorim Jaggif4797922014-08-04 22:49:41 +0200682 public interface OnVerticalChangedListener {
683 void onVerticalChanged(boolean isVertical);
684 }
Daniel Sandler8956dbb2011-04-22 07:55:02 -0400685}