From 49fa016a98cef9940c883b3f620a0e90537a204e Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Wed, 11 Jan 2017 09:21:56 -0500 Subject: [PATCH] Move navigation bar logic to its own class Start hacking away at PhoneStatusBar by trying to pull out as much NavigationBar logic as possible. Test: runtest systemui Change-Id: I23b904428be31b91f0747fd60c9f6e0dd323eb44 --- .../res/layout/navigation_bar_window.xml | 26 + .../systemui/SysUiServiceProvider.java | 23 + .../src/com/android/systemui/SystemUI.java | 2 +- .../android/systemui/SystemUIApplication.java | 6 +- .../fragments/FragmentHostManager.java | 2 +- .../systemui/statusbar/BaseStatusBar.java | 38 - .../systemui/statusbar/CommandQueue.java | 154 ++-- .../systemui/statusbar/car/CarStatusBar.java | 32 +- .../statusbar/phone/LightBarController.java | 35 +- .../phone/LightBarTransitionsController.java | 14 + .../phone/NavigationBarFragment.java | 666 ++++++++++++++++++ .../phone/NavigationBarInflaterView.java | 14 - .../statusbar/phone/NavigationBarView.java | 6 +- .../phone/NotificationPanelView.java | 2 +- .../statusbar/phone/PhoneStatusBar.java | 515 ++------------ .../systemui/statusbar/tv/TvStatusBar.java | 9 - .../phone/NavigationBarFragmentTest.java | 40 ++ .../systemui/utils/TestableContext.java | 14 +- 18 files changed, 980 insertions(+), 618 deletions(-) create mode 100644 packages/SystemUI/res/layout/navigation_bar_window.xml create mode 100644 packages/SystemUI/src/com/android/systemui/SysUiServiceProvider.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java diff --git a/packages/SystemUI/res/layout/navigation_bar_window.xml b/packages/SystemUI/res/layout/navigation_bar_window.xml new file mode 100644 index 0000000000000..051bf3ac3faf8 --- /dev/null +++ b/packages/SystemUI/res/layout/navigation_bar_window.xml @@ -0,0 +1,26 @@ + + + + + diff --git a/packages/SystemUI/src/com/android/systemui/SysUiServiceProvider.java b/packages/SystemUI/src/com/android/systemui/SysUiServiceProvider.java new file mode 100644 index 0000000000000..c4470cd846718 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/SysUiServiceProvider.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui; + +/** + * The interface for getting core components of SysUI. Exists for Testability + * since tests don't have SystemUIApplication as their ApplicationContext. + */ +public interface SysUiServiceProvider { + T getComponent(Class interfaceType); +} diff --git a/packages/SystemUI/src/com/android/systemui/SystemUI.java b/packages/SystemUI/src/com/android/systemui/SystemUI.java index f30baee35f3a2..6b30a89d51c01 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUI.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUI.java @@ -25,7 +25,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Map; -public abstract class SystemUI { +public abstract class SystemUI implements SysUiServiceProvider { public Context mContext; public Map, Object> mComponents; diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java index 19880230186ae..bd4e3dcbbd486 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java @@ -55,7 +55,7 @@ import java.util.Map; /** * Application class for SystemUI. */ -public class SystemUIApplication extends Application { +public class SystemUIApplication extends Application implements SysUiServiceProvider { private static final String TAG = "SystemUIService"; private static final boolean DEBUG = false; @@ -239,4 +239,8 @@ public class SystemUIApplication extends Application { public SystemUI[] getServices() { return mServices; } + + public static T getComponent(Context context, Class interfaceType) { + return ((SysUiServiceProvider) context.getApplicationContext()).getComponent(interfaceType); + } } diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java index 6d0e77c061320..57857ccb8cc68 100644 --- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java +++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java @@ -52,7 +52,7 @@ public class FragmentHostManager { private FragmentLifecycleCallbacks mLifecycleCallbacks; FragmentHostManager(Context context, FragmentService manager, View rootView) { - mContext = PluginManager.getInstance(context).getAllPluginContext(context); + mContext = context; mManager = manager; mRootView = rootView; mConfigChanges.applyNewConfig(context.getResources()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index db099bc15472f..561b46984ff04 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -185,9 +185,6 @@ public abstract class BaseStatusBar extends SystemUI implements protected int mLayoutDirection = -1; // invalid protected AccessibilityManager mAccessibilityManager; - // on-screen navigation buttons - protected NavigationBarView mNavigationBarView = null; - protected boolean mDeviceInteractive; protected boolean mVisible; @@ -238,8 +235,6 @@ public abstract class BaseStatusBar extends SystemUI implements protected WindowManager mWindowManager; protected IWindowManager mWindowManagerService; - protected abstract void refreshLayout(int layoutDirection); - protected Display mDisplay; private boolean mDeviceProvisioned = false; @@ -945,8 +940,6 @@ public abstract class BaseStatusBar extends SystemUI implements @Override protected void onConfigurationChanged(Configuration newConfig) { - final Locale locale = mContext.getResources().getConfiguration().locale; - final int ld = TextUtils.getLayoutDirectionFromLocale(locale); final float fontScale = newConfig.fontScale; final int density = newConfig.densityDpi; if (density != mDensity || mFontScale != fontScale) { @@ -954,16 +947,6 @@ public abstract class BaseStatusBar extends SystemUI implements mDensity = density; mFontScale = fontScale; } - if (! locale.equals(mLocale) || ld != mLayoutDirection) { - if (DEBUG) { - Log.v(TAG, String.format( - "config changed locale/LD: %s (%d) -> %s (%d)", mLocale, mLayoutDirection, - locale, ld)); - } - mLocale = locale; - mLayoutDirection = ld; - refreshLayout(ld); - } } protected void onDensityOrFontScaleChanged() { @@ -1285,26 +1268,6 @@ public abstract class BaseStatusBar extends SystemUI implements protected abstract View getStatusBarView(); - protected View.OnTouchListener mRecentsPreloadOnTouchListener = new View.OnTouchListener() { - // additional optimization when we have software system buttons - start loading the recent - // tasks on touch down - @Override - public boolean onTouch(View v, MotionEvent event) { - int action = event.getAction() & MotionEvent.ACTION_MASK; - if (action == MotionEvent.ACTION_DOWN) { - preloadRecents(); - } else if (action == MotionEvent.ACTION_CANCEL) { - cancelPreloadingRecents(); - } else if (action == MotionEvent.ACTION_UP) { - if (!v.isPressed()) { - cancelPreloadingRecents(); - } - - } - return false; - } - }; - /** * Toggle docking the app window * @@ -2256,7 +2219,6 @@ public abstract class BaseStatusBar extends SystemUI implements protected abstract void setAreThereNotifications(); protected abstract void updateNotifications(); - public abstract boolean shouldDisableNavbarGestures(); public abstract void addNotification(StatusBarNotification notification, RankingMap ranking, Entry oldEntry); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index a3e4d5b6db542..fed28e32b0bb6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -32,6 +32,8 @@ import com.android.internal.statusbar.IStatusBar; import com.android.internal.statusbar.StatusBarIcon; import com.android.systemui.SystemUI; +import java.util.ArrayList; + /** * This class takes the functions from IStatusBar that come in on * binder pool threads and posts messages to get them onto the main @@ -91,7 +93,7 @@ public class CommandQueue extends IStatusBar.Stub { private static final String SHOW_IME_SWITCHER_KEY = "showImeSwitcherKey"; private final Object mLock = new Object(); - private Callbacks[] mCallbacks = new Callbacks[0]; + private ArrayList mCallbacks = new ArrayList<>(); private Handler mHandler = new H(Looper.getMainLooper()); /** @@ -144,15 +146,11 @@ public class CommandQueue extends IStatusBar.Stub { } public void addCallbacks(Callbacks callbacks) { - Callbacks[] newArray = new Callbacks[mCallbacks.length + 1]; - for (int i = 0; i < newArray.length - 1; i++) { - newArray[i] = mCallbacks[i]; - if (newArray[i] == callbacks) { - throw new IllegalArgumentException("Callback was already added"); - } - } - newArray[newArray.length - 1] = callbacks; - mCallbacks = newArray; + mCallbacks.add(callbacks); + } + + public void removeCallbacks(Callbacks callbacks) { + mCallbacks.remove(callbacks); } public void setIcon(String slot, StatusBarIcon icon) { @@ -427,182 +425,182 @@ public class CommandQueue extends IStatusBar.Stub { switch (msg.arg1) { case OP_SET_ICON: { Pair p = (Pair) msg.obj; - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].setIcon(p.first, p.second); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).setIcon(p.first, p.second); } break; } case OP_REMOVE_ICON: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].removeIcon((String) msg.obj); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).removeIcon((String) msg.obj); } break; } break; } case MSG_DISABLE: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].disable(msg.arg1, msg.arg2, true /* animate */); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).disable(msg.arg1, msg.arg2, true /* animate */); } break; case MSG_EXPAND_NOTIFICATIONS: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].animateExpandNotificationsPanel(); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).animateExpandNotificationsPanel(); } break; case MSG_COLLAPSE_PANELS: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].animateCollapsePanels(0); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).animateCollapsePanels(0); } break; case MSG_EXPAND_SETTINGS: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].animateExpandSettingsPanel((String) msg.obj); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).animateExpandSettingsPanel((String) msg.obj); } break; case MSG_SET_SYSTEMUI_VISIBILITY: SomeArgs args = (SomeArgs) msg.obj; - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].setSystemUiVisibility(args.argi1, args.argi2, args.argi3, + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).setSystemUiVisibility(args.argi1, args.argi2, args.argi3, args.argi4, (Rect) args.arg1, (Rect) args.arg2); } args.recycle(); break; case MSG_TOP_APP_WINDOW_CHANGED: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].topAppWindowChanged(msg.arg1 != 0); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).topAppWindowChanged(msg.arg1 != 0); } break; case MSG_SHOW_IME_BUTTON: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].setImeWindowStatus((IBinder) msg.obj, msg.arg1, msg.arg2, + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).setImeWindowStatus((IBinder) msg.obj, msg.arg1, msg.arg2, msg.getData().getBoolean(SHOW_IME_SWITCHER_KEY, false)); } break; case MSG_SHOW_RECENT_APPS: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].showRecentApps(msg.arg1 != 0, msg.arg2 != 0); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).showRecentApps(msg.arg1 != 0, msg.arg2 != 0); } break; case MSG_HIDE_RECENT_APPS: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].hideRecentApps(msg.arg1 != 0, msg.arg2 != 0); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).hideRecentApps(msg.arg1 != 0, msg.arg2 != 0); } break; case MSG_TOGGLE_RECENT_APPS: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].toggleRecentApps(); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).toggleRecentApps(); } break; case MSG_PRELOAD_RECENT_APPS: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].preloadRecentApps(); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).preloadRecentApps(); } break; case MSG_CANCEL_PRELOAD_RECENT_APPS: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].cancelPreloadRecentApps(); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).cancelPreloadRecentApps(); } break; case MSG_DISMISS_KEYBOARD_SHORTCUTS: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].dismissKeyboardShortcutsMenu(); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).dismissKeyboardShortcutsMenu(); } break; case MSG_TOGGLE_KEYBOARD_SHORTCUTS: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].toggleKeyboardShortcutsMenu(msg.arg1); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).toggleKeyboardShortcutsMenu(msg.arg1); } break; case MSG_SET_WINDOW_STATE: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].setWindowState(msg.arg1, msg.arg2); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).setWindowState(msg.arg1, msg.arg2); } break; case MSG_BUZZ_BEEP_BLINKED: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].buzzBeepBlinked(); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).buzzBeepBlinked(); } break; case MSG_NOTIFICATION_LIGHT_OFF: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].notificationLightOff(); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).notificationLightOff(); } break; case MSG_NOTIFICATION_LIGHT_PULSE: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].notificationLightPulse((Integer) msg.obj, msg.arg1, msg.arg2); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).notificationLightPulse((Integer) msg.obj, msg.arg1, msg.arg2); } break; case MSG_SHOW_SCREEN_PIN_REQUEST: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].showScreenPinningRequest(msg.arg1); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).showScreenPinningRequest(msg.arg1); } break; case MSG_APP_TRANSITION_PENDING: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].appTransitionPending(); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).appTransitionPending(); } break; case MSG_APP_TRANSITION_CANCELLED: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].appTransitionCancelled(); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).appTransitionCancelled(); } break; case MSG_APP_TRANSITION_STARTING: - for (int i = 0; i < mCallbacks.length; i++) { + for (int i = 0; i < mCallbacks.size(); i++) { Pair data = (Pair) msg.obj; - mCallbacks[i].appTransitionStarting(data.first, data.second); + mCallbacks.get(i).appTransitionStarting(data.first, data.second); } break; case MSG_APP_TRANSITION_FINISHED: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].appTransitionFinished(); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).appTransitionFinished(); } break; case MSG_ASSIST_DISCLOSURE: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].showAssistDisclosure(); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).showAssistDisclosure(); } break; case MSG_START_ASSIST: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].startAssist((Bundle) msg.obj); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).startAssist((Bundle) msg.obj); } break; case MSG_CAMERA_LAUNCH_GESTURE: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].onCameraLaunchGestureDetected(msg.arg1); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).onCameraLaunchGestureDetected(msg.arg1); } break; case MSG_SHOW_TV_PICTURE_IN_PICTURE_MENU: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].showTvPictureInPictureMenu(); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).showTvPictureInPictureMenu(); } break; case MSG_ADD_QS_TILE: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].addQsTile((ComponentName) msg.obj); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).addQsTile((ComponentName) msg.obj); } break; case MSG_REMOVE_QS_TILE: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].remQsTile((ComponentName) msg.obj); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).remQsTile((ComponentName) msg.obj); } break; case MSG_CLICK_QS_TILE: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].clickTile((ComponentName) msg.obj); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).clickTile((ComponentName) msg.obj); } break; case MSG_TOGGLE_APP_SPLIT_SCREEN: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].toggleSplitScreen(); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).toggleSplitScreen(); } break; case MSG_HANDLE_SYSNAV_KEY: - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].handleSystemNavigationKey(msg.arg1); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).handleSystemNavigationKey(msg.arg1); } break; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index dd5832b886ee3..7adb36d615d1a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -64,6 +64,7 @@ public class CarStatusBar extends PhoneStatusBar implements private ConnectedDeviceSignalController mConnectedDeviceSignalController; private View mSignalsView; + private CarNavigationBarView mNavigationBarView; @Override public void start() { @@ -121,7 +122,17 @@ public class CarStatusBar extends PhoneStatusBar implements } @Override - protected void addNavigationBar() { + protected void createNavigationBar() { + if (mNavigationBarView != null) { + return; + } + + mCarNavigationBar = + (CarNavigationBarView) View.inflate(mContext, R.layout.car_navigation_bar, null); + mController = new CarNavigationBarController(mContext, mCarNavigationBar, + this /* ActivityStarter*/); + mNavigationBarView = mCarNavigationBar; + mCarNavigationBar.getBarTransitions().setAlwaysOpaque(true); WindowManager.LayoutParams lp = new WindowManager.LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_NAVIGATION_BAR, @@ -137,19 +148,6 @@ public class CarStatusBar extends PhoneStatusBar implements mWindowManager.addView(mNavigationBarView, lp); } - @Override - protected void createNavigationBarView(Context context) { - if (mNavigationBarView != null) { - return; - } - mCarNavigationBar = - (CarNavigationBarView) View.inflate(context, R.layout.car_navigation_bar, null); - mController = new CarNavigationBarController(context, mCarNavigationBar, - this /* ActivityStarter*/); - mNavigationBarView = mCarNavigationBar; - mCarNavigationBar.getBarTransitions().setAlwaysOpaque(true); - } - @Override public void showBatteryView() { if (Log.isLoggable(TAG, Log.DEBUG)) { @@ -191,12 +189,6 @@ public class CarStatusBar extends PhoneStatusBar implements mContext.registerReceiver(mPackageChangeReceiver, filter); } - @Override - protected void repositionNavigationBar() { - // The navigation bar for a vehicle will not need to be repositioned, as it is always - // set at the bottom. - } - public boolean hasDockedTask() { return Recents.getSystemServices().hasDockedTask(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java index b5358a187d5a3..6dddf1832f6cf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java @@ -34,8 +34,8 @@ public class LightBarController implements BatteryController.BatteryStateChangeC private final StatusBarIconController mStatusBarIconController; private final BatteryController mBatteryController; private FingerprintUnlockController mFingerprintUnlockController; - private final NavigationBarView mNavigationBarView; + private LightBarTransitionsController mNavigationBarController; private int mSystemUiVisibility; private int mFullscreenStackVisibility; private int mDockedStackVisibility; @@ -50,22 +50,24 @@ public class LightBarController implements BatteryController.BatteryStateChangeC private final Rect mLastDockedBounds = new Rect(); public LightBarController(StatusBarIconController statusBarIconController, - NavigationBarView navigationBarView, BatteryController batteryController) { mStatusBarIconController = statusBarIconController; - mNavigationBarView = navigationBarView; mBatteryController = batteryController; batteryController.addCallback(this); } + public void setNavigationBar(LightBarTransitionsController navigationBar) { + mNavigationBarController = navigationBar; + } + public void setFingerprintUnlockController( FingerprintUnlockController fingerprintUnlockController) { mFingerprintUnlockController = fingerprintUnlockController; } - public void onSystemUiVisibilityChanged(int vis, int fullscreenStackVis, int dockedStackVis, + public void onSystemUiVisibilityChanged(int fullscreenStackVis, int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, boolean sbModeChanged, - int statusBarMode, boolean nbModeChanged, int navigationBarMode) { + int statusBarMode) { int oldFullscreen = mFullscreenStackVisibility; int newFullscreen = (oldFullscreen & ~mask) | (fullscreenStackVis & mask); int diffFullscreen = newFullscreen ^ oldFullscreen; @@ -84,6 +86,15 @@ public class LightBarController implements BatteryController.BatteryStateChangeC updateStatus(fullscreenStackBounds, dockedStackBounds); } + mFullscreenStackVisibility = newFullscreen; + mDockedStackVisibility = newDocked; + mLastStatusBarMode = statusBarMode; + mLastFullscreenBounds.set(fullscreenStackBounds); + mLastDockedBounds.set(dockedStackBounds); + } + + public void onNavigationVisibilityChanged(int vis, int mask, boolean nbModeChanged, + int navigationBarMode) { int oldVis = mSystemUiVisibility; int newVis = (oldVis & ~mask) | (vis & mask); int diffVis = newVis ^ oldVis; @@ -95,19 +106,15 @@ public class LightBarController implements BatteryController.BatteryStateChangeC updateNavigation(); } } - mFullscreenStackVisibility = newFullscreen; - mDockedStackVisibility = newDocked; mSystemUiVisibility = newVis; - mLastStatusBarMode = statusBarMode; mLastNavigationBarMode = navigationBarMode; - mLastFullscreenBounds.set(fullscreenStackBounds); - mLastDockedBounds.set(dockedStackBounds); } private void reevaluate() { - onSystemUiVisibilityChanged(mSystemUiVisibility, mFullscreenStackVisibility, + onSystemUiVisibilityChanged(mFullscreenStackVisibility, mDockedStackVisibility, 0 /* mask */, mLastFullscreenBounds, mLastDockedBounds, - true /* sbModeChange*/, mLastStatusBarMode, true /* nbModeChange*/, + true /* sbModeChange*/, mLastStatusBarMode); + onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */, true /* nbModeChanged */, mLastNavigationBarMode); } @@ -169,8 +176,8 @@ public class LightBarController implements BatteryController.BatteryStateChangeC } private void updateNavigation() { - if (mNavigationBarView != null) { - mNavigationBarView.getLightTransitionsController().setIconsDark( + if (mNavigationBarController != null) { + mNavigationBarController.setIconsDark( mNavigationLight, animateChange()); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java index 1d4d2d1c7bf0f..0f9f0563b7fea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.phone; import android.animation.ValueAnimator; +import android.os.Bundle; import android.os.Handler; import android.os.SystemClock; @@ -28,6 +29,7 @@ import com.android.systemui.Interpolators; public class LightBarTransitionsController { public static final long DEFAULT_TINT_ANIMATION_DURATION = 120; + private static final String EXTRA_DARK_INTENSITY = "dark_intensity"; private final Handler mHandler; private final DarkIntensityApplier mApplier; @@ -40,6 +42,7 @@ public class LightBarTransitionsController { private float mPendingDarkIntensity; private ValueAnimator mTintAnimator; private float mDarkIntensity; + private float mNextDarkIntensity; private final Runnable mTransitionDeferringDoneRunnable = new Runnable() { @Override @@ -53,6 +56,16 @@ public class LightBarTransitionsController { mHandler = new Handler(); } + public void saveState(Bundle outState) { + float intensity = mTintAnimator != null && mTintAnimator.isRunning() + ? mNextDarkIntensity : mDarkIntensity; + outState.putFloat(EXTRA_DARK_INTENSITY, intensity); + } + + public void restoreState(Bundle savedInstanceState) { + setIconTintInternal(savedInstanceState.getFloat(EXTRA_DARK_INTENSITY, 0)); + } + public void appTransitionPending() { mTransitionPending = true; } @@ -119,6 +132,7 @@ public class LightBarTransitionsController { if (mDarkIntensity == targetDarkIntensity) { return; } + mNextDarkIntensity = targetDarkIntensity; mTintAnimator = ValueAnimator.ofFloat(mDarkIntensity, targetDarkIntensity); mTintAnimator.addUpdateListener( animation -> setIconTintInternal((Float) animation.getAnimatedValue())); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java new file mode 100644 index 0000000000000..c0f245c10af6e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -0,0 +1,666 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.statusbar.phone; + +import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT; +import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN; +import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; +import static android.app.StatusBarManager.windowStateToString; + +import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT; +import static com.android.systemui.statusbar.phone.PhoneStatusBar.DEBUG_WINDOW_STATE; +import static com.android.systemui.statusbar.phone.PhoneStatusBar.dumpBarTransitions; + +import android.annotation.Nullable; +import android.app.ActivityManager; +import android.app.ActivityManagerNative; +import android.app.Fragment; +import android.app.IActivityManager; +import android.app.StatusBarManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.Configuration; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.inputmethodservice.InputMethodService; +import android.os.Binder; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.PowerManager; +import android.os.RemoteException; +import android.os.UserHandle; +import android.telecom.TelecomManager; +import android.text.TextUtils; +import android.util.Log; +import android.view.IRotationWatcher.Stub; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.view.WindowManager.LayoutParams; +import android.view.WindowManagerGlobal; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.keyguard.LatencyTracker; +import com.android.systemui.R; +import com.android.systemui.SystemUIApplication; +import com.android.systemui.assist.AssistManager; +import com.android.systemui.fragments.FragmentHostManager; +import com.android.systemui.fragments.FragmentHostManager.FragmentListener; +import com.android.systemui.recents.Recents; +import com.android.systemui.stackdivider.Divider; +import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.CommandQueue.Callbacks; +import com.android.systemui.statusbar.policy.KeyButtonView; +import com.android.systemui.statusbar.stack.StackStateAnimator; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.Locale; + +/** + * Fragment containing the NavigationBarFragment. Contains logic for what happens + * on clicks and view states of the nav bar. + */ +public class NavigationBarFragment extends Fragment implements Callbacks { + + private static final String TAG = "NavigationBar"; + private static final boolean DEBUG = false; + private static final String EXTRA_DISABLE_STATE = "disabled_state"; + + /** Allow some time inbetween the long press for back and recents. */ + private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200; + + protected NavigationBarView mNavigationBarView = null; + protected AssistManager mAssistManager; + + private int mNavigationBarWindowState = WINDOW_STATE_SHOWING; + + private int mNavigationIconHints = 0; + private int mNavigationBarMode; + protected AccessibilityManager mAccessibilityManager; + + private int mDisabledFlags1; + private PhoneStatusBar mPhoneStatusBar; + private Recents mRecents; + private Divider mDivider; + private WindowManager mWindowManager; + private CommandQueue mCommandQueue; + private long mLastLockToAppLongPress; + + private Locale mLocale; + private int mLayoutDirection; + + private int mSystemUiVisibility; + private LightBarController mLightBarController; + private boolean mKeyguardGoingAway; + + public boolean mHomeBlockedThisTouch; + + // ----- Fragment Lifecycle Callbacks ----- + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mCommandQueue = SystemUIApplication.getComponent(getContext(), CommandQueue.class); + mCommandQueue.addCallbacks(this); + mPhoneStatusBar = SystemUIApplication.getComponent(getContext(), PhoneStatusBar.class); + mRecents = SystemUIApplication.getComponent(getContext(), Recents.class); + mDivider = SystemUIApplication.getComponent(getContext(), Divider.class); + mWindowManager = getContext().getSystemService(WindowManager.class); + mAccessibilityManager = getContext().getSystemService(AccessibilityManager.class); + if (savedInstanceState != null) { + mDisabledFlags1 = savedInstanceState.getInt(EXTRA_DISABLE_STATE, 0); + } + + try { + WindowManagerGlobal.getWindowManagerService() + .watchRotation(mRotationWatcher); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + mCommandQueue.removeCallbacks(this); + try { + WindowManagerGlobal.getWindowManagerService() + .removeRotationWatcher(mRotationWatcher); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.navigation_bar, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + mNavigationBarView = (NavigationBarView) view; + + mNavigationBarView.setDisabledFlags(mDisabledFlags1); + mNavigationBarView.setComponents(mRecents, mDivider); + mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged); + mNavigationBarView.setOnTouchListener(this::onNavigationTouch); + if (savedInstanceState != null) { + mNavigationBarView.getLightTransitionsController().restoreState(savedInstanceState); + } + + prepareNavigationBarView(); + checkNavBarModes(); + + IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF); + filter.addAction(Intent.ACTION_SCREEN_ON); + getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null); + PowerManager pm = getContext().getSystemService(PowerManager.class); + notifyNavigationBarScreenOn(pm.isScreenOn()); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + getContext().unregisterReceiver(mBroadcastReceiver); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putInt(EXTRA_DISABLE_STATE, mDisabledFlags1); + if (mNavigationBarView != null) { + mNavigationBarView.getLightTransitionsController().saveState(outState); + } + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + final Locale locale = getContext().getResources().getConfiguration().locale; + final int ld = TextUtils.getLayoutDirectionFromLocale(locale); + if (!locale.equals(mLocale) || ld != mLayoutDirection) { + if (DEBUG) { + Log.v(TAG, String.format( + "config changed locale/LD: %s (%d) -> %s (%d)", mLocale, mLayoutDirection, + locale, ld)); + } + mLocale = locale; + mLayoutDirection = ld; + refreshLayout(ld); + } + repositionNavigationBar(); + } + + @Override + public void dump(String prefix, FileDescriptor fd, PrintWriter pw, String[] args) { + if (mNavigationBarView != null) { + pw.print(" mNavigationBarWindowState="); + pw.println(windowStateToString(mNavigationBarWindowState)); + pw.print(" mNavigationBarMode="); + pw.println(BarTransitions.modeToString(mNavigationBarMode)); + dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions()); + } + + pw.print(" mNavigationBarView="); + if (mNavigationBarView == null) { + pw.println("null"); + } else { + mNavigationBarView.dump(fd, pw, args); + } + } + + // ----- CommandQueue Callbacks ----- + + @Override + public void setImeWindowStatus(IBinder token, int vis, int backDisposition, + boolean showImeSwitcher) { + boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0; + int hints = mNavigationIconHints; + if ((backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS) || imeShown) { + hints |= NAVIGATION_HINT_BACK_ALT; + } else { + hints &= ~NAVIGATION_HINT_BACK_ALT; + } + if (showImeSwitcher) { + hints |= NAVIGATION_HINT_IME_SHOWN; + } else { + hints &= ~NAVIGATION_HINT_IME_SHOWN; + } + if (hints == mNavigationIconHints) return; + + mNavigationIconHints = hints; + + if (mNavigationBarView != null) { + mNavigationBarView.setNavigationIconHints(hints); + } + mPhoneStatusBar.checkBarModes(); + } + + @Override + public void topAppWindowChanged(boolean showMenu) { + if (mNavigationBarView != null) { + mNavigationBarView.setMenuVisibility(showMenu); + } + } + + @Override + public void setWindowState(int window, int state) { + if (mNavigationBarView != null + && window == StatusBarManager.WINDOW_NAVIGATION_BAR + && mNavigationBarWindowState != state) { + mNavigationBarWindowState = state; + if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state)); + } + } + + @Override + public void appTransitionPending() { + mNavigationBarView.getLightTransitionsController().appTransitionPending(); + } + + @Override + public void appTransitionCancelled() { + mNavigationBarView.getLightTransitionsController().appTransitionCancelled(); + } + + @Override + public void appTransitionStarting(long startTime, long duration) { + if (mKeyguardGoingAway) return; + doAppTransitionStarting(startTime, duration); + } + + /** + * Calls appTransitionStarting for the nav bar regardless of whether keyguard is going away. + * public so PhoneStatusBar can force this when needed. + */ + public void doAppTransitionStarting(long startTime, long duration) { + mNavigationBarView.getLightTransitionsController().appTransitionStarting(startTime, + duration); + } + + // Injected from PhoneStatusBar at creation. + public void setCurrentSysuiVisibility(int systemUiVisibility) { + mSystemUiVisibility = systemUiVisibility; + mNavigationBarMode = mPhoneStatusBar.computeBarMode(0, mSystemUiVisibility, + View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT, + View.NAVIGATION_BAR_TRANSPARENT); + checkNavBarModes(); + mPhoneStatusBar.touchAutoHide(); + mLightBarController.onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */, + true /* nbModeChanged */, mNavigationBarMode); + } + + @Override + public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, + int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) { + final int oldVal = mSystemUiVisibility; + final int newVal = (oldVal & ~mask) | (vis & mask); + final int diff = newVal ^ oldVal; + boolean nbModeChanged = false; + if (diff != 0) { + mSystemUiVisibility = newVal; + + // update navigation bar mode + final int nbMode = getView() == null + ? -1 : mPhoneStatusBar.computeBarMode(oldVal, newVal, + View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT, + View.NAVIGATION_BAR_TRANSPARENT); + nbModeChanged = nbMode != -1; + if (nbModeChanged) { + if (mNavigationBarMode != nbMode) { + mNavigationBarMode = nbMode; + checkNavBarModes(); + } + mPhoneStatusBar.touchAutoHide(); + } + } + + mLightBarController.onNavigationVisibilityChanged(vis, mask, nbModeChanged, + mNavigationBarMode); + } + + @Override + public void disable(int state1, int state2, boolean animate) { + // All navigation bar flags are in state1. + int masked = state1 & (StatusBarManager.DISABLE_HOME + | StatusBarManager.DISABLE_RECENT + | StatusBarManager.DISABLE_BACK + | StatusBarManager.DISABLE_SEARCH); + if (masked != mDisabledFlags1) { + mDisabledFlags1 = masked; + if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state1); + } + } + + // ----- Internal stuffz ----- + + private void refreshLayout(int layoutDirection) { + if (mNavigationBarView != null) { + mNavigationBarView.setLayoutDirection(layoutDirection); + } + } + + private boolean shouldDisableNavbarGestures() { + return !mPhoneStatusBar.isDeviceProvisioned() + || (mDisabledFlags1 & StatusBarManager.DISABLE_SEARCH) != 0; + } + + private void repositionNavigationBar() { + if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return; + + prepareNavigationBarView(); + + mWindowManager.updateViewLayout((View) mNavigationBarView.getParent(), + ((View) mNavigationBarView.getParent()).getLayoutParams()); + } + + private void notifyNavigationBarScreenOn(boolean screenOn) { + mNavigationBarView.notifyScreenOn(screenOn); + } + + private void prepareNavigationBarView() { + mNavigationBarView.reorient(); + + ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton(); + recentsButton.setOnClickListener(this::onRecentsClick); + recentsButton.setOnTouchListener(this::onRecentsTouch); + recentsButton.setLongClickable(true); + recentsButton.setOnLongClickListener(this::onLongPressBackRecents); + + ButtonDispatcher backButton = mNavigationBarView.getBackButton(); + backButton.setLongClickable(true); + backButton.setOnLongClickListener(this::onLongPressBackRecents); + + ButtonDispatcher homeButton = mNavigationBarView.getHomeButton(); + homeButton.setOnTouchListener(this::onHomeTouch); + homeButton.setOnLongClickListener(this::onHomeLongClick); + + if (mAssistManager != null) { + mAssistManager.onConfigurationChanged(); + } + } + + private boolean onHomeTouch(View v, MotionEvent event) { + if (mHomeBlockedThisTouch && event.getActionMasked() != MotionEvent.ACTION_DOWN) { + return true; + } + // If an incoming call is ringing, HOME is totally disabled. + // (The user is already on the InCallUI at this point, + // and his ONLY options are to answer or reject the call.) + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + mHomeBlockedThisTouch = false; + TelecomManager telecomManager = + getContext().getSystemService(TelecomManager.class); + if (telecomManager != null && telecomManager.isRinging()) { + if (mPhoneStatusBar.isKeyguardShowing()) { + Log.i(TAG, "Ignoring HOME; there's a ringing incoming call. " + + "No heads up"); + mHomeBlockedThisTouch = true; + return true; + } + } + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + mPhoneStatusBar.awakenDreams(); + break; + } + return false; + } + + private void onVerticalChanged(boolean isVertical) { + if (mAssistManager != null) { + // TODO: Clean this up. + mAssistManager.onConfigurationChanged(); + } + mPhoneStatusBar.setQsScrimEnabled(!isVertical); + } + + private boolean onNavigationTouch(View v, MotionEvent event) { + mPhoneStatusBar.checkUserAutohide(v, event); + return false; + } + + private boolean onHomeLongClick(View v) { + if (shouldDisableNavbarGestures()) { + return false; + } + MetricsLogger.action(getContext(), MetricsEvent.ACTION_ASSIST_LONG_PRESS); + mAssistManager.startAssist(new Bundle() /* args */); + mPhoneStatusBar.awakenDreams(); + if (mNavigationBarView != null) { + mNavigationBarView.abortCurrentGesture(); + } + return true; + } + + // additional optimization when we have software system buttons - start loading the recent + // tasks on touch down + private boolean onRecentsTouch(View v, MotionEvent event) { + int action = event.getAction() & MotionEvent.ACTION_MASK; + if (action == MotionEvent.ACTION_DOWN) { + mCommandQueue.preloadRecentApps(); + } else if (action == MotionEvent.ACTION_CANCEL) { + mCommandQueue.cancelPreloadRecentApps(); + } else if (action == MotionEvent.ACTION_UP) { + if (!v.isPressed()) { + mCommandQueue.cancelPreloadRecentApps(); + } + } + return false; + } + + private void onRecentsClick(View v) { + if (LatencyTracker.isEnabled(getContext())) { + LatencyTracker.getInstance(getContext()).onActionStart( + LatencyTracker.ACTION_TOGGLE_RECENTS); + } + mPhoneStatusBar.awakenDreams(); + mCommandQueue.toggleRecentApps(); + } + + /** + * This handles long-press of both back and recents. They are + * handled together to capture them both being long-pressed + * at the same time to exit screen pinning (lock task). + * + * When accessibility mode is on, only a long-press from recents + * is required to exit. + * + * In all other circumstances we try to pass through long-press events + * for Back, so that apps can still use it. Which can be from two things. + * 1) Not currently in screen pinning (lock task). + * 2) Back is long-pressed without recents. + */ + private boolean onLongPressBackRecents(View v) { + try { + boolean sendBackLongPress = false; + IActivityManager activityManager = ActivityManagerNative.getDefault(); + boolean touchExplorationEnabled = mAccessibilityManager.isTouchExplorationEnabled(); + boolean inLockTaskMode = activityManager.isInLockTaskMode(); + if (inLockTaskMode && !touchExplorationEnabled) { + long time = System.currentTimeMillis(); + // If we recently long-pressed the other button then they were + // long-pressed 'together' + if ((time - mLastLockToAppLongPress) < LOCK_TO_APP_GESTURE_TOLERENCE) { + activityManager.stopLockTaskMode(); + // When exiting refresh disabled flags. + mNavigationBarView.setDisabledFlags(mDisabledFlags1, true); + return true; + } else if ((v.getId() == R.id.back) + && !mNavigationBarView.getRecentsButton().getCurrentView().isPressed()) { + // If we aren't pressing recents right now then they presses + // won't be together, so send the standard long-press action. + sendBackLongPress = true; + } + mLastLockToAppLongPress = time; + } else { + // If this is back still need to handle sending the long-press event. + if (v.getId() == R.id.back) { + sendBackLongPress = true; + } else if (touchExplorationEnabled && inLockTaskMode) { + // When in accessibility mode a long press that is recents (not back) + // should stop lock task. + activityManager.stopLockTaskMode(); + // When exiting refresh disabled flags. + mNavigationBarView.setDisabledFlags(mDisabledFlags1, true); + return true; + } else if (v.getId() == R.id.recent_apps) { + return onLongPressRecents(); + } + } + if (sendBackLongPress) { + KeyButtonView keyButtonView = (KeyButtonView) v; + keyButtonView.sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS); + keyButtonView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); + return true; + } + } catch (RemoteException e) { + Log.d(TAG, "Unable to reach activity manager", e); + } + return false; + } + + private boolean onLongPressRecents() { + if (mRecents == null || !ActivityManager.supportsMultiWindow() + || !mDivider.getView().getSnapAlgorithm() + .isSplitScreenFeasible()) { + return false; + } + + return mPhoneStatusBar.toggleSplitScreenMode(MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS, + MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS); + } + + // ----- Methods that PhoneStatusBar talks to (should be minimized) ----- + + public void setAssistManager(AssistManager assistManager) { + mAssistManager = assistManager; + } + + public void setLightBarController(LightBarController lightBarController) { + mLightBarController = lightBarController; + mLightBarController.setNavigationBar(mNavigationBarView.getLightTransitionsController()); + } + + public boolean isSemiTransparent() { + return mNavigationBarMode == MODE_SEMI_TRANSPARENT; + } + + public void onKeyguardOccludedChanged(boolean keyguardOccluded) { + mNavigationBarView.onKeyguardOccludedChanged(keyguardOccluded); + } + + public void disableAnimationsDuringHide(long delay) { + mNavigationBarView.setLayoutTransitionsEnabled(false); + mNavigationBarView.postDelayed(() -> mNavigationBarView.setLayoutTransitionsEnabled(true), + delay + StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE); + } + + public void setKeyguardGoingAway(boolean keyguardGoingAway) { + mKeyguardGoingAway = keyguardGoingAway; + } + + public BarTransitions getBarTransitions() { + return mNavigationBarView.getBarTransitions(); + } + + public void checkNavBarModes() { + mPhoneStatusBar.checkBarMode(mNavigationBarMode, + mNavigationBarWindowState, mNavigationBarView.getBarTransitions()); + } + + public void finishBarAnimations() { + mNavigationBarView.getBarTransitions().finishAnimations(); + } + + private final Stub mRotationWatcher = new Stub() { + @Override + public void onRotationChanged(int rotation) throws RemoteException { + // We need this to be scheduled as early as possible to beat the redrawing of + // window in response to the orientation change. + Handler h = getView().getHandler(); + Message msg = Message.obtain(h, () -> { + if (mNavigationBarView != null + && mNavigationBarView.needsReorient(rotation)) { + repositionNavigationBar(); + } + }); + msg.setAsynchronous(true); + h.sendMessageAtFrontOfQueue(msg); + } + }; + + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (Intent.ACTION_SCREEN_OFF.equals(action)) { + notifyNavigationBarScreenOn(false); + } else if (Intent.ACTION_SCREEN_ON.equals(action)) { + notifyNavigationBarScreenOn(true); + } + } + }; + + public static View create(Context context, FragmentListener listener) { + WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.TYPE_NAVIGATION_BAR, + WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH + | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH + | WindowManager.LayoutParams.FLAG_SLIPPERY, + PixelFormat.TRANSLUCENT); + lp.token = new Binder(); + // this will allow the navbar to run in an overlay on devices that support this + if (ActivityManager.isHighEndGfx()) { + lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; + } + lp.setTitle("NavigationBar"); + lp.windowAnimations = 0; + + View navigationBarView = LayoutInflater.from(context).inflate( + R.layout.navigation_bar_window, null); + + if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + navigationBarView); + if (navigationBarView == null) return null; + + context.getSystemService(WindowManager.class).addView(navigationBarView, lp); + FragmentHostManager fragmentHost = FragmentHostManager.get(navigationBarView); + NavigationBarFragment fragment = new NavigationBarFragment(); + fragmentHost.getFragmentManager().beginTransaction() + .replace(R.id.navigation_bar_frame, fragment, TAG) + .commit(); + fragmentHost.addTagListener(TAG, listener); + return navigationBarView; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java index b2b093cf0033a..b6feb0eba058b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java @@ -70,7 +70,6 @@ public class NavigationBarInflaterView extends FrameLayout protected LayoutInflater mLayoutInflater; protected LayoutInflater mLandscapeInflater; - private int mDensity; protected FrameLayout mRot0; protected FrameLayout mRot90; @@ -86,7 +85,6 @@ public class NavigationBarInflaterView extends FrameLayout public NavigationBarInflaterView(Context context, AttributeSet attrs) { super(context, attrs); - mDensity = context.getResources().getConfiguration().densityDpi; createInflaters(); Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); @@ -102,18 +100,6 @@ public class NavigationBarInflaterView extends FrameLayout mLandscapeInflater = LayoutInflater.from(mContext.createConfigurationContext(landscape)); } - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - if (mDensity != newConfig.densityDpi) { - mDensity = newConfig.densityDpi; - createInflaters(); - inflateChildren(); - clearViews(); - inflateLayout(mCurrentLayout); - } - } - @Override protected void onFinishInflate() { super.onFinishInflate(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index d22f42144fddb..31c78c8f911de 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -434,7 +434,6 @@ public class NavigationBarView extends FrameLayout implements PluginListener