Loading packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java +114 −3 Original line number Diff line number Diff line Loading @@ -70,6 +70,7 @@ import android.graphics.Insets; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.os.Binder; import android.os.Bundle; import android.os.Handler; Loading @@ -91,6 +92,8 @@ import android.view.MotionEvent; import android.view.Surface; import android.view.View; import android.view.ViewTreeObserver; import android.view.ViewTreeObserver.InternalInsetsInfo; import android.view.ViewTreeObserver.OnComputeInternalInsetsListener; import android.view.WindowInsetsController.Appearance; import android.view.WindowInsetsController.Behavior; import android.view.WindowManager; Loading Loading @@ -121,6 +124,7 @@ import com.android.systemui.navigationbar.buttons.ButtonDispatcher; import com.android.systemui.navigationbar.buttons.DeadZone; import com.android.systemui.navigationbar.buttons.KeyButtonView; import com.android.systemui.navigationbar.buttons.RotationContextButton; import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler; import com.android.systemui.navigationbar.gestural.QuickswitchOrientedNavHandle; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.recents.OverviewProxyService; Loading Loading @@ -153,6 +157,7 @@ import com.android.wm.shell.pip.Pip; import java.io.PrintWriter; import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.function.Consumer; Loading Loading @@ -199,12 +204,14 @@ public class NavigationBar extends ViewController<NavigationBarView> implements private final Optional<Recents> mRecentsOptional; private final DeviceConfigProxy mDeviceConfigProxy; private final NavigationBarTransitions mNavigationBarTransitions; private final EdgeBackGestureHandler mEdgeBackGestureHandler; private final Optional<BackAnimation> mBackAnimation; private final Handler mHandler; private final UiEventLogger mUiEventLogger; private final NavBarHelper mNavBarHelper; private final NotificationShadeDepthController mNotificationShadeDepthController; private final UserContextProvider mUserContextProvider; private final OnComputeInternalInsetsListener mOnComputeInternalInsetsListener; private NavigationBarFrame mFrame; private @WindowVisibleState int mNavigationBarWindowState = WINDOW_STATE_SHOWING; Loading Loading @@ -516,6 +523,7 @@ public class NavigationBar extends ViewController<NavigationBarView> implements DeadZone deadZone, DeviceConfigProxy deviceConfigProxy, NavigationBarTransitions navigationBarTransitions, EdgeBackGestureHandler edgeBackGestureHandler, Optional<BackAnimation> backAnimation, UserContextProvider userContextProvider) { super(navigationBarView); Loading @@ -542,6 +550,7 @@ public class NavigationBar extends ViewController<NavigationBarView> implements mDeadZone = deadZone; mDeviceConfigProxy = deviceConfigProxy; mNavigationBarTransitions = navigationBarTransitions; mEdgeBackGestureHandler = edgeBackGestureHandler; mBackAnimation = backAnimation; mHandler = mainHandler; mUiEventLogger = uiEventLogger; Loading @@ -555,6 +564,29 @@ public class NavigationBar extends ViewController<NavigationBarView> implements mInputMethodManager = inputMethodManager; mUserContextProvider = userContextProvider; mOnComputeInternalInsetsListener = info -> { // When the nav bar is in 2-button or 3-button mode, or when IME is visible in fully // gestural mode, the entire nav bar should be touchable. if (!mEdgeBackGestureHandler.isHandlingGestures()) { // We're in 2/3 button mode OR back button force-shown in SUW if (!mImeVisible) { // IME not showing, take all touches info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_FRAME); } if (!mView.isImeRenderingNavButtons()) { // IME showing but not drawing any buttons, take all touches info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_FRAME); } } // When in gestural and the IME is showing, don't use the nearest region since it will // take gesture space away from the IME info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION); info.touchableRegion.set(getButtonLocations(false /* includeFloatingButtons */, false /* inScreen */, false /* useNearestRegion */)); }; mView.setEdgeBackGestureHandler(mEdgeBackGestureHandler); mNavBarMode = mNavigationModeController.addListener(mModeChangedListener); } Loading @@ -569,6 +601,7 @@ public class NavigationBar extends ViewController<NavigationBarView> implements mView.setBarTransitions(mNavigationBarTransitions); mView.setTouchHandler(mTouchHandler); mView.setNavBarMode(mNavBarMode); mEdgeBackGestureHandler.setStateChangeCallback(mView::updateStates); mView.updateRotationButton(); mView.setVisibility( Loading Loading @@ -646,11 +679,14 @@ public class NavigationBar extends ViewController<NavigationBarView> implements mView.setNavBarMode(mNavBarMode); mView.setUpdateActiveTouchRegionsCallback( () -> mOverviewProxyService.onActiveNavBarRegionChanges( mView.getButtonLocations( getButtonLocations( true /* includeFloatingButtons */, true /* inScreen */, true /* useNearestRegion */))); mView.getViewTreeObserver().addOnComputeInternalInsetsListener( mOnComputeInternalInsetsListener); mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater); mPipOptional.ifPresent(mView::addPipExclusionBoundsChangeListener); Loading Loading @@ -721,6 +757,8 @@ public class NavigationBar extends ViewController<NavigationBarView> implements mOrientationHandle.getViewTreeObserver().removeOnGlobalLayoutListener( mOrientationHandleGlobalLayoutListener); } mView.getViewTreeObserver().removeOnComputeInternalInsetsListener( mOnComputeInternalInsetsListener); mHandler.removeCallbacks(mAutoDim); mHandler.removeCallbacks(mOnVariableDurationHomeLongClick); mHandler.removeCallbacks(mEnableLayoutTransitions); Loading Loading @@ -1044,8 +1082,8 @@ public class NavigationBar extends ViewController<NavigationBarView> implements } private void handleTransientChanged() { mView.onTransientStateChanged(mTransientShown, mTransientShownFromGestureOnSystemBar); mEdgeBackGestureHandler.onNavBarTransientStateChanged(mTransientShown); final int transitionMode = transitionMode(mTransientShown, mAppearance); if (updateTransitionMode(transitionMode) && mLightBarController != null) { mLightBarController.onNavigationBarModeChanged(transitionMode); Loading Loading @@ -1639,6 +1677,79 @@ public class NavigationBar extends ViewController<NavigationBarView> implements mNavigationIconHints = hints; } /** * @param includeFloatingButtons Whether to include the floating rotation and overlay button in * the region for all the buttons * @param inScreenSpace Whether to return values in screen space or window space * @param useNearestRegion Whether to use the nearest region instead of the actual button bounds * @return */ Region getButtonLocations(boolean includeFloatingButtons, boolean inScreenSpace, boolean useNearestRegion) { if (useNearestRegion && !inScreenSpace) { // We currently don't support getting the nearest region in anything but screen space useNearestRegion = false; } Region region = new Region(); Map<View, Rect> touchRegionCache = mView.getButtonTouchRegionCache(); updateButtonLocation( region, touchRegionCache, mView.getBackButton(), inScreenSpace, useNearestRegion); updateButtonLocation( region, touchRegionCache, mView.getHomeButton(), inScreenSpace, useNearestRegion); updateButtonLocation(region, touchRegionCache, mView.getRecentsButton(), inScreenSpace, useNearestRegion); updateButtonLocation(region, touchRegionCache, mView.getImeSwitchButton(), inScreenSpace, useNearestRegion); updateButtonLocation( region, touchRegionCache, mView.getAccessibilityButton(), inScreenSpace, useNearestRegion); if (includeFloatingButtons && mView.getFloatingRotationButton().isVisible()) { // Note: this button is floating so the nearest region doesn't apply updateButtonLocation( region, mView.getFloatingRotationButton().getCurrentView(), inScreenSpace); } else { updateButtonLocation(region, touchRegionCache, mView.getRotateSuggestionButton(), inScreenSpace, useNearestRegion); } return region; } private void updateButtonLocation( Region region, Map<View, Rect> touchRegionCache, ButtonDispatcher button, boolean inScreenSpace, boolean useNearestRegion) { if (button == null) { return; } View view = button.getCurrentView(); if (view == null || !button.isVisible()) { return; } // If the button is tappable from perspective of NearestTouchFrame, then we'll // include the regions where the tap is valid instead of just the button layout location if (useNearestRegion && touchRegionCache.containsKey(view)) { region.op(touchRegionCache.get(view), Region.Op.UNION); return; } updateButtonLocation(region, view, inScreenSpace); } private void updateButtonLocation(Region region, View view, boolean inScreenSpace) { Rect bounds = new Rect(); if (inScreenSpace) { view.getBoundsOnScreen(bounds); } else { int[] location = new int[2]; view.getLocationInWindow(location); bounds.set(location[0], location[1], location[0] + view.getWidth(), location[1] + view.getHeight()); } region.op(bounds, Region.Op.UNION); } private final ModeChangedListener mModeChangedListener = new ModeChangedListener() { @Override public void onNavigationModeChanged(int mode) { Loading packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarModule.java +9 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.view.WindowManager; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.DisplayId; import com.android.systemui.navigationbar.NavigationBarComponent.NavigationBarScope; import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler; import dagger.Module; import dagger.Provides; Loading Loading @@ -55,6 +56,14 @@ public interface NavigationBarModule { return barView.findViewById(R.id.navigation_bar_view); } /** */ @Provides @NavigationBarScope static EdgeBackGestureHandler provideEdgeBackGestureHandler( EdgeBackGestureHandler.Factory factory, @DisplayId Context context) { return factory.create(context); } /** A WindowManager specific to the display's context. */ @Provides @NavigationBarScope Loading packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java +8 −116 Original line number Diff line number Diff line Loading @@ -41,8 +41,6 @@ import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; import android.graphics.Region.Op; import android.os.Bundle; import android.util.AttributeSet; import android.util.Log; Loading @@ -53,8 +51,6 @@ import android.view.MotionEvent; import android.view.Surface; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver.InternalInsetsInfo; import android.view.ViewTreeObserver.OnComputeInternalInsetsListener; import android.view.WindowInsets; import android.view.WindowInsetsController.Behavior; import android.view.WindowManager; Loading Loading @@ -93,7 +89,6 @@ import com.android.wm.shell.back.BackAnimation; import com.android.wm.shell.pip.Pip; import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.concurrent.Executor; Loading Loading @@ -123,11 +118,6 @@ public class NavigationBarView extends FrameLayout { private int mNavBarMode; private boolean mImeDrawsImeNavBar; private final Region mTmpRegion = new Region(); private final int[] mTmpPosition = new int[2]; private Rect mTmpBounds = new Rect(); private Map<View, Rect> mButtonFullTouchableRegions = new HashMap<>(); private KeyButtonDrawable mBackIcon; private KeyButtonDrawable mHomeDefaultIcon; private KeyButtonDrawable mRecentIcon; Loading @@ -138,7 +128,6 @@ public class NavigationBarView extends FrameLayout { private EdgeBackGestureHandler mEdgeBackGestureHandler; private final DeadZone mDeadZone; private boolean mDeadZoneConsuming = false; private NavigationBarTransitions mBarTransitions; @Nullable private AutoHideController mAutoHideController; Loading @@ -152,7 +141,6 @@ public class NavigationBarView extends FrameLayout { private boolean mUseCarModeUi = false; private boolean mInCarMode = false; private boolean mDockedStackExists; private boolean mImeVisible; private boolean mScreenOn = true; private final SparseArray<ButtonDispatcher> mButtonDispatchers = new SparseArray<>(); Loading Loading @@ -272,31 +260,6 @@ public class NavigationBarView extends FrameLayout { } }; private final OnComputeInternalInsetsListener mOnComputeInternalInsetsListener = info -> { // When the nav bar is in 2-button or 3-button mode, or when the back button is force-shown // while in gesture nav in SUW, the entire nav bar should be touchable. if (!mEdgeBackGestureHandler.isHandlingGestures()) { // We're in 2/3 button mode OR back button force-shown in SUW if (!mImeVisible) { // IME not showing, take all touches info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_FRAME); return; } if (!isImeRenderingNavButtons()) { // IME showing but not drawing any buttons, take all touches info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_FRAME); return; } } // When in gestural and the IME is showing, don't use the nearest region since it will take // gesture space away from the IME info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION); info.touchableRegion.set(getButtonLocations(false /* includeFloatingButtons */, false /* inScreen */, false /* useNearestRegion */)); }; private final RotationButtonUpdatesCallback mRotationButtonListener = new RotationButtonUpdatesCallback() { @Override Loading @@ -315,13 +278,6 @@ public class NavigationBarView extends FrameLayout { } }; private final Consumer<Boolean> mNavbarOverlayVisibilityChangeCallback = (visible) -> { if (visible) { mAutoHideController.touchAutoHide(); } notifyActiveTouchRegions(); }; public NavigationBarView(Context context, AttributeSet attrs) { super(context, attrs); Loading Loading @@ -380,9 +336,6 @@ public class NavigationBarView extends FrameLayout { mNavColorSampleMargin = getResources() .getDimensionPixelSize(R.dimen.navigation_handle_sample_horizontal_margin); mEdgeBackGestureHandler = Dependency.get(EdgeBackGestureHandler.Factory.class) .create(mContext); mEdgeBackGestureHandler.setStateChangeCallback(this::updateStates); Executor backgroundExecutor = Dependency.get(Dependency.BACKGROUND_EXECUTOR); mRegionSamplingHelper = new RegionSamplingHelper(this, new RegionSamplingHelper.SamplingCallback() { Loading @@ -409,6 +362,10 @@ public class NavigationBarView extends FrameLayout { }, backgroundExecutor); } public void setEdgeBackGestureHandler(EdgeBackGestureHandler edgeBackGestureHandler) { mEdgeBackGestureHandler = edgeBackGestureHandler; } void setBarTransitions(NavigationBarTransitions navigationBarTransitions) { mBarTransitions = navigationBarTransitions; } Loading Loading @@ -681,8 +638,7 @@ public class NavigationBarView extends FrameLayout { if (!visible) { mTransitionListener.onBackAltCleared(); } mImeVisible = visible; mRotationButtonController.getRotationButton().setCanShowRotationButton(!mImeVisible); mRotationButtonController.getRotationButton().setCanShowRotationButton(!visible); } void setDisabledFlags(int disabledFlags, SysUiState sysUiState) { Loading Loading @@ -774,7 +730,7 @@ public class NavigationBarView extends FrameLayout { /** * Returns whether the IME is currently visible and drawing the nav buttons. */ private boolean isImeRenderingNavButtons() { boolean isImeRenderingNavButtons() { return mImeDrawsImeNavBar && mImeCanRenderGesturalNavButtons && (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0; Loading Loading @@ -1003,75 +959,14 @@ public class NavigationBarView extends FrameLayout { notifyActiveTouchRegions(); } private void updateButtonTouchRegionCache() { Map<View, Rect> getButtonTouchRegionCache() { FrameLayout navBarLayout = mIsVertical ? mNavigationInflaterView.mVertical : mNavigationInflaterView.mHorizontal; mButtonFullTouchableRegions = ((NearestTouchFrame) navBarLayout return ((NearestTouchFrame) navBarLayout .findViewById(R.id.nav_buttons)).getFullTouchableChildRegions(); } /** * @param includeFloatingButtons Whether to include the floating rotation and overlay button in * the region for all the buttons * @param inScreenSpace Whether to return values in screen space or window space * @param useNearestRegion Whether to use the nearest region instead of the actual button bounds * @return */ Region getButtonLocations(boolean includeFloatingButtons, boolean inScreenSpace, boolean useNearestRegion) { // TODO: move this method to NavigationBar. // TODO: don't use member variables for temp storage like mTmpRegion. if (useNearestRegion && !inScreenSpace) { // We currently don't support getting the nearest region in anything but screen space useNearestRegion = false; } mTmpRegion.setEmpty(); updateButtonTouchRegionCache(); updateButtonLocation(getBackButton(), inScreenSpace, useNearestRegion); updateButtonLocation(getHomeButton(), inScreenSpace, useNearestRegion); updateButtonLocation(getRecentsButton(), inScreenSpace, useNearestRegion); updateButtonLocation(getImeSwitchButton(), inScreenSpace, useNearestRegion); updateButtonLocation(getAccessibilityButton(), inScreenSpace, useNearestRegion); if (includeFloatingButtons && mFloatingRotationButton.isVisible()) { // Note: this button is floating so the nearest region doesn't apply updateButtonLocation(mFloatingRotationButton.getCurrentView(), inScreenSpace); } else { updateButtonLocation(getRotateSuggestionButton(), inScreenSpace, useNearestRegion); } return mTmpRegion; } private void updateButtonLocation(ButtonDispatcher button, boolean inScreenSpace, boolean useNearestRegion) { if (button == null) { return; } View view = button.getCurrentView(); if (view == null || !button.isVisible()) { return; } // If the button is tappable from perspective of NearestTouchFrame, then we'll // include the regions where the tap is valid instead of just the button layout location if (useNearestRegion && mButtonFullTouchableRegions.containsKey(view)) { mTmpRegion.op(mButtonFullTouchableRegions.get(view), Op.UNION); return; } updateButtonLocation(view, inScreenSpace); } private void updateButtonLocation(View view, boolean inScreenSpace) { if (inScreenSpace) { view.getBoundsOnScreen(mTmpBounds); } else { view.getLocationInWindow(mTmpPosition); mTmpBounds.set(mTmpPosition[0], mTmpPosition[1], mTmpPosition[0] + view.getWidth(), mTmpPosition[1] + view.getHeight()); } mTmpRegion.op(mTmpBounds, Op.UNION); } private void updateOrientationViews() { mHorizontal = findViewById(R.id.horizontal); mVertical = findViewById(R.id.vertical); Loading Loading @@ -1272,7 +1167,6 @@ public class NavigationBarView extends FrameLayout { mRotationButtonController.registerListeners(); } getViewTreeObserver().addOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener); updateNavButtonIcons(); } Loading @@ -1288,8 +1182,6 @@ public class NavigationBarView extends FrameLayout { } mEdgeBackGestureHandler.onNavBarDetached(); getViewTreeObserver().removeOnComputeInternalInsetsListener( mOnComputeInternalInsetsListener); } public void dump(PrintWriter pw) { Loading packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java +4 −5 Original line number Diff line number Diff line Loading @@ -60,6 +60,7 @@ import android.view.Display; import android.view.DisplayInfo; import android.view.MotionEvent; import android.view.View; import android.view.ViewTreeObserver; import android.view.WindowInsets; import android.view.WindowManager; import android.view.WindowMetrics; Loading Loading @@ -164,7 +165,7 @@ public class NavigationBarTest extends SysuiTestCase { @Mock private UiEventLogger mUiEventLogger; @Mock EdgeBackGestureHandler.Factory mEdgeBackGestureHandlerFactory; private ViewTreeObserver mViewTreeObserver; @Mock EdgeBackGestureHandler mEdgeBackGestureHandler; NavBarHelper mNavBarHelper; Loading Loading @@ -199,8 +200,6 @@ public class NavigationBarTest extends SysuiTestCase { public void setup() throws Exception { MockitoAnnotations.initMocks(this); when(mEdgeBackGestureHandlerFactory.create(any(Context.class))) .thenReturn(mEdgeBackGestureHandler); when(mLightBarcontrollerFactory.create(any(Context.class))).thenReturn(mLightBarController); when(mAutoHideControllerFactory.create(any(Context.class))).thenReturn(mAutoHideController); when(mNavigationBarView.getHomeButton()).thenReturn(mHomeButton); Loading @@ -213,6 +212,7 @@ public class NavigationBarTest extends SysuiTestCase { when(mNavigationBarTransitions.getLightTransitionsController()) .thenReturn(mLightBarTransitionsController); when(mStatusBarKeyguardViewManager.isNavBarVisible()).thenReturn(true); when(mNavigationBarView.getViewTreeObserver()).thenReturn(mViewTreeObserver); when(mUserContextProvider.createCurrentUserContext(any(Context.class))) .thenReturn(mContext); setupSysuiDependency(); Loading @@ -222,8 +222,6 @@ public class NavigationBarTest extends SysuiTestCase { mDependency.injectMockDependency(KeyguardStateController.class); mDependency.injectTestDependency(StatusBarStateController.class, mStatusBarStateController); mDependency.injectMockDependency(NavigationBarController.class); mDependency.injectTestDependency(EdgeBackGestureHandler.Factory.class, mEdgeBackGestureHandlerFactory); mDependency.injectTestDependency(OverviewProxyService.class, mOverviewProxyService); mDependency.injectTestDependency(NavigationModeController.class, mNavigationModeController); TestableLooper.get(this).runWithLooper(() -> { Loading Loading @@ -463,6 +461,7 @@ public class NavigationBarTest extends SysuiTestCase { mDeadZone, mDeviceConfigProxyFake, mNavigationBarTransitions, mEdgeBackGestureHandler, Optional.of(mock(BackAnimation.class)), mUserContextProvider)); } Loading Loading
packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java +114 −3 Original line number Diff line number Diff line Loading @@ -70,6 +70,7 @@ import android.graphics.Insets; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.os.Binder; import android.os.Bundle; import android.os.Handler; Loading @@ -91,6 +92,8 @@ import android.view.MotionEvent; import android.view.Surface; import android.view.View; import android.view.ViewTreeObserver; import android.view.ViewTreeObserver.InternalInsetsInfo; import android.view.ViewTreeObserver.OnComputeInternalInsetsListener; import android.view.WindowInsetsController.Appearance; import android.view.WindowInsetsController.Behavior; import android.view.WindowManager; Loading Loading @@ -121,6 +124,7 @@ import com.android.systemui.navigationbar.buttons.ButtonDispatcher; import com.android.systemui.navigationbar.buttons.DeadZone; import com.android.systemui.navigationbar.buttons.KeyButtonView; import com.android.systemui.navigationbar.buttons.RotationContextButton; import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler; import com.android.systemui.navigationbar.gestural.QuickswitchOrientedNavHandle; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.recents.OverviewProxyService; Loading Loading @@ -153,6 +157,7 @@ import com.android.wm.shell.pip.Pip; import java.io.PrintWriter; import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.function.Consumer; Loading Loading @@ -199,12 +204,14 @@ public class NavigationBar extends ViewController<NavigationBarView> implements private final Optional<Recents> mRecentsOptional; private final DeviceConfigProxy mDeviceConfigProxy; private final NavigationBarTransitions mNavigationBarTransitions; private final EdgeBackGestureHandler mEdgeBackGestureHandler; private final Optional<BackAnimation> mBackAnimation; private final Handler mHandler; private final UiEventLogger mUiEventLogger; private final NavBarHelper mNavBarHelper; private final NotificationShadeDepthController mNotificationShadeDepthController; private final UserContextProvider mUserContextProvider; private final OnComputeInternalInsetsListener mOnComputeInternalInsetsListener; private NavigationBarFrame mFrame; private @WindowVisibleState int mNavigationBarWindowState = WINDOW_STATE_SHOWING; Loading Loading @@ -516,6 +523,7 @@ public class NavigationBar extends ViewController<NavigationBarView> implements DeadZone deadZone, DeviceConfigProxy deviceConfigProxy, NavigationBarTransitions navigationBarTransitions, EdgeBackGestureHandler edgeBackGestureHandler, Optional<BackAnimation> backAnimation, UserContextProvider userContextProvider) { super(navigationBarView); Loading @@ -542,6 +550,7 @@ public class NavigationBar extends ViewController<NavigationBarView> implements mDeadZone = deadZone; mDeviceConfigProxy = deviceConfigProxy; mNavigationBarTransitions = navigationBarTransitions; mEdgeBackGestureHandler = edgeBackGestureHandler; mBackAnimation = backAnimation; mHandler = mainHandler; mUiEventLogger = uiEventLogger; Loading @@ -555,6 +564,29 @@ public class NavigationBar extends ViewController<NavigationBarView> implements mInputMethodManager = inputMethodManager; mUserContextProvider = userContextProvider; mOnComputeInternalInsetsListener = info -> { // When the nav bar is in 2-button or 3-button mode, or when IME is visible in fully // gestural mode, the entire nav bar should be touchable. if (!mEdgeBackGestureHandler.isHandlingGestures()) { // We're in 2/3 button mode OR back button force-shown in SUW if (!mImeVisible) { // IME not showing, take all touches info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_FRAME); } if (!mView.isImeRenderingNavButtons()) { // IME showing but not drawing any buttons, take all touches info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_FRAME); } } // When in gestural and the IME is showing, don't use the nearest region since it will // take gesture space away from the IME info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION); info.touchableRegion.set(getButtonLocations(false /* includeFloatingButtons */, false /* inScreen */, false /* useNearestRegion */)); }; mView.setEdgeBackGestureHandler(mEdgeBackGestureHandler); mNavBarMode = mNavigationModeController.addListener(mModeChangedListener); } Loading @@ -569,6 +601,7 @@ public class NavigationBar extends ViewController<NavigationBarView> implements mView.setBarTransitions(mNavigationBarTransitions); mView.setTouchHandler(mTouchHandler); mView.setNavBarMode(mNavBarMode); mEdgeBackGestureHandler.setStateChangeCallback(mView::updateStates); mView.updateRotationButton(); mView.setVisibility( Loading Loading @@ -646,11 +679,14 @@ public class NavigationBar extends ViewController<NavigationBarView> implements mView.setNavBarMode(mNavBarMode); mView.setUpdateActiveTouchRegionsCallback( () -> mOverviewProxyService.onActiveNavBarRegionChanges( mView.getButtonLocations( getButtonLocations( true /* includeFloatingButtons */, true /* inScreen */, true /* useNearestRegion */))); mView.getViewTreeObserver().addOnComputeInternalInsetsListener( mOnComputeInternalInsetsListener); mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater); mPipOptional.ifPresent(mView::addPipExclusionBoundsChangeListener); Loading Loading @@ -721,6 +757,8 @@ public class NavigationBar extends ViewController<NavigationBarView> implements mOrientationHandle.getViewTreeObserver().removeOnGlobalLayoutListener( mOrientationHandleGlobalLayoutListener); } mView.getViewTreeObserver().removeOnComputeInternalInsetsListener( mOnComputeInternalInsetsListener); mHandler.removeCallbacks(mAutoDim); mHandler.removeCallbacks(mOnVariableDurationHomeLongClick); mHandler.removeCallbacks(mEnableLayoutTransitions); Loading Loading @@ -1044,8 +1082,8 @@ public class NavigationBar extends ViewController<NavigationBarView> implements } private void handleTransientChanged() { mView.onTransientStateChanged(mTransientShown, mTransientShownFromGestureOnSystemBar); mEdgeBackGestureHandler.onNavBarTransientStateChanged(mTransientShown); final int transitionMode = transitionMode(mTransientShown, mAppearance); if (updateTransitionMode(transitionMode) && mLightBarController != null) { mLightBarController.onNavigationBarModeChanged(transitionMode); Loading Loading @@ -1639,6 +1677,79 @@ public class NavigationBar extends ViewController<NavigationBarView> implements mNavigationIconHints = hints; } /** * @param includeFloatingButtons Whether to include the floating rotation and overlay button in * the region for all the buttons * @param inScreenSpace Whether to return values in screen space or window space * @param useNearestRegion Whether to use the nearest region instead of the actual button bounds * @return */ Region getButtonLocations(boolean includeFloatingButtons, boolean inScreenSpace, boolean useNearestRegion) { if (useNearestRegion && !inScreenSpace) { // We currently don't support getting the nearest region in anything but screen space useNearestRegion = false; } Region region = new Region(); Map<View, Rect> touchRegionCache = mView.getButtonTouchRegionCache(); updateButtonLocation( region, touchRegionCache, mView.getBackButton(), inScreenSpace, useNearestRegion); updateButtonLocation( region, touchRegionCache, mView.getHomeButton(), inScreenSpace, useNearestRegion); updateButtonLocation(region, touchRegionCache, mView.getRecentsButton(), inScreenSpace, useNearestRegion); updateButtonLocation(region, touchRegionCache, mView.getImeSwitchButton(), inScreenSpace, useNearestRegion); updateButtonLocation( region, touchRegionCache, mView.getAccessibilityButton(), inScreenSpace, useNearestRegion); if (includeFloatingButtons && mView.getFloatingRotationButton().isVisible()) { // Note: this button is floating so the nearest region doesn't apply updateButtonLocation( region, mView.getFloatingRotationButton().getCurrentView(), inScreenSpace); } else { updateButtonLocation(region, touchRegionCache, mView.getRotateSuggestionButton(), inScreenSpace, useNearestRegion); } return region; } private void updateButtonLocation( Region region, Map<View, Rect> touchRegionCache, ButtonDispatcher button, boolean inScreenSpace, boolean useNearestRegion) { if (button == null) { return; } View view = button.getCurrentView(); if (view == null || !button.isVisible()) { return; } // If the button is tappable from perspective of NearestTouchFrame, then we'll // include the regions where the tap is valid instead of just the button layout location if (useNearestRegion && touchRegionCache.containsKey(view)) { region.op(touchRegionCache.get(view), Region.Op.UNION); return; } updateButtonLocation(region, view, inScreenSpace); } private void updateButtonLocation(Region region, View view, boolean inScreenSpace) { Rect bounds = new Rect(); if (inScreenSpace) { view.getBoundsOnScreen(bounds); } else { int[] location = new int[2]; view.getLocationInWindow(location); bounds.set(location[0], location[1], location[0] + view.getWidth(), location[1] + view.getHeight()); } region.op(bounds, Region.Op.UNION); } private final ModeChangedListener mModeChangedListener = new ModeChangedListener() { @Override public void onNavigationModeChanged(int mode) { Loading
packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarModule.java +9 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.view.WindowManager; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.DisplayId; import com.android.systemui.navigationbar.NavigationBarComponent.NavigationBarScope; import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler; import dagger.Module; import dagger.Provides; Loading Loading @@ -55,6 +56,14 @@ public interface NavigationBarModule { return barView.findViewById(R.id.navigation_bar_view); } /** */ @Provides @NavigationBarScope static EdgeBackGestureHandler provideEdgeBackGestureHandler( EdgeBackGestureHandler.Factory factory, @DisplayId Context context) { return factory.create(context); } /** A WindowManager specific to the display's context. */ @Provides @NavigationBarScope Loading
packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java +8 −116 Original line number Diff line number Diff line Loading @@ -41,8 +41,6 @@ import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; import android.graphics.Region.Op; import android.os.Bundle; import android.util.AttributeSet; import android.util.Log; Loading @@ -53,8 +51,6 @@ import android.view.MotionEvent; import android.view.Surface; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver.InternalInsetsInfo; import android.view.ViewTreeObserver.OnComputeInternalInsetsListener; import android.view.WindowInsets; import android.view.WindowInsetsController.Behavior; import android.view.WindowManager; Loading Loading @@ -93,7 +89,6 @@ import com.android.wm.shell.back.BackAnimation; import com.android.wm.shell.pip.Pip; import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.concurrent.Executor; Loading Loading @@ -123,11 +118,6 @@ public class NavigationBarView extends FrameLayout { private int mNavBarMode; private boolean mImeDrawsImeNavBar; private final Region mTmpRegion = new Region(); private final int[] mTmpPosition = new int[2]; private Rect mTmpBounds = new Rect(); private Map<View, Rect> mButtonFullTouchableRegions = new HashMap<>(); private KeyButtonDrawable mBackIcon; private KeyButtonDrawable mHomeDefaultIcon; private KeyButtonDrawable mRecentIcon; Loading @@ -138,7 +128,6 @@ public class NavigationBarView extends FrameLayout { private EdgeBackGestureHandler mEdgeBackGestureHandler; private final DeadZone mDeadZone; private boolean mDeadZoneConsuming = false; private NavigationBarTransitions mBarTransitions; @Nullable private AutoHideController mAutoHideController; Loading @@ -152,7 +141,6 @@ public class NavigationBarView extends FrameLayout { private boolean mUseCarModeUi = false; private boolean mInCarMode = false; private boolean mDockedStackExists; private boolean mImeVisible; private boolean mScreenOn = true; private final SparseArray<ButtonDispatcher> mButtonDispatchers = new SparseArray<>(); Loading Loading @@ -272,31 +260,6 @@ public class NavigationBarView extends FrameLayout { } }; private final OnComputeInternalInsetsListener mOnComputeInternalInsetsListener = info -> { // When the nav bar is in 2-button or 3-button mode, or when the back button is force-shown // while in gesture nav in SUW, the entire nav bar should be touchable. if (!mEdgeBackGestureHandler.isHandlingGestures()) { // We're in 2/3 button mode OR back button force-shown in SUW if (!mImeVisible) { // IME not showing, take all touches info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_FRAME); return; } if (!isImeRenderingNavButtons()) { // IME showing but not drawing any buttons, take all touches info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_FRAME); return; } } // When in gestural and the IME is showing, don't use the nearest region since it will take // gesture space away from the IME info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION); info.touchableRegion.set(getButtonLocations(false /* includeFloatingButtons */, false /* inScreen */, false /* useNearestRegion */)); }; private final RotationButtonUpdatesCallback mRotationButtonListener = new RotationButtonUpdatesCallback() { @Override Loading @@ -315,13 +278,6 @@ public class NavigationBarView extends FrameLayout { } }; private final Consumer<Boolean> mNavbarOverlayVisibilityChangeCallback = (visible) -> { if (visible) { mAutoHideController.touchAutoHide(); } notifyActiveTouchRegions(); }; public NavigationBarView(Context context, AttributeSet attrs) { super(context, attrs); Loading Loading @@ -380,9 +336,6 @@ public class NavigationBarView extends FrameLayout { mNavColorSampleMargin = getResources() .getDimensionPixelSize(R.dimen.navigation_handle_sample_horizontal_margin); mEdgeBackGestureHandler = Dependency.get(EdgeBackGestureHandler.Factory.class) .create(mContext); mEdgeBackGestureHandler.setStateChangeCallback(this::updateStates); Executor backgroundExecutor = Dependency.get(Dependency.BACKGROUND_EXECUTOR); mRegionSamplingHelper = new RegionSamplingHelper(this, new RegionSamplingHelper.SamplingCallback() { Loading @@ -409,6 +362,10 @@ public class NavigationBarView extends FrameLayout { }, backgroundExecutor); } public void setEdgeBackGestureHandler(EdgeBackGestureHandler edgeBackGestureHandler) { mEdgeBackGestureHandler = edgeBackGestureHandler; } void setBarTransitions(NavigationBarTransitions navigationBarTransitions) { mBarTransitions = navigationBarTransitions; } Loading Loading @@ -681,8 +638,7 @@ public class NavigationBarView extends FrameLayout { if (!visible) { mTransitionListener.onBackAltCleared(); } mImeVisible = visible; mRotationButtonController.getRotationButton().setCanShowRotationButton(!mImeVisible); mRotationButtonController.getRotationButton().setCanShowRotationButton(!visible); } void setDisabledFlags(int disabledFlags, SysUiState sysUiState) { Loading Loading @@ -774,7 +730,7 @@ public class NavigationBarView extends FrameLayout { /** * Returns whether the IME is currently visible and drawing the nav buttons. */ private boolean isImeRenderingNavButtons() { boolean isImeRenderingNavButtons() { return mImeDrawsImeNavBar && mImeCanRenderGesturalNavButtons && (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0; Loading Loading @@ -1003,75 +959,14 @@ public class NavigationBarView extends FrameLayout { notifyActiveTouchRegions(); } private void updateButtonTouchRegionCache() { Map<View, Rect> getButtonTouchRegionCache() { FrameLayout navBarLayout = mIsVertical ? mNavigationInflaterView.mVertical : mNavigationInflaterView.mHorizontal; mButtonFullTouchableRegions = ((NearestTouchFrame) navBarLayout return ((NearestTouchFrame) navBarLayout .findViewById(R.id.nav_buttons)).getFullTouchableChildRegions(); } /** * @param includeFloatingButtons Whether to include the floating rotation and overlay button in * the region for all the buttons * @param inScreenSpace Whether to return values in screen space or window space * @param useNearestRegion Whether to use the nearest region instead of the actual button bounds * @return */ Region getButtonLocations(boolean includeFloatingButtons, boolean inScreenSpace, boolean useNearestRegion) { // TODO: move this method to NavigationBar. // TODO: don't use member variables for temp storage like mTmpRegion. if (useNearestRegion && !inScreenSpace) { // We currently don't support getting the nearest region in anything but screen space useNearestRegion = false; } mTmpRegion.setEmpty(); updateButtonTouchRegionCache(); updateButtonLocation(getBackButton(), inScreenSpace, useNearestRegion); updateButtonLocation(getHomeButton(), inScreenSpace, useNearestRegion); updateButtonLocation(getRecentsButton(), inScreenSpace, useNearestRegion); updateButtonLocation(getImeSwitchButton(), inScreenSpace, useNearestRegion); updateButtonLocation(getAccessibilityButton(), inScreenSpace, useNearestRegion); if (includeFloatingButtons && mFloatingRotationButton.isVisible()) { // Note: this button is floating so the nearest region doesn't apply updateButtonLocation(mFloatingRotationButton.getCurrentView(), inScreenSpace); } else { updateButtonLocation(getRotateSuggestionButton(), inScreenSpace, useNearestRegion); } return mTmpRegion; } private void updateButtonLocation(ButtonDispatcher button, boolean inScreenSpace, boolean useNearestRegion) { if (button == null) { return; } View view = button.getCurrentView(); if (view == null || !button.isVisible()) { return; } // If the button is tappable from perspective of NearestTouchFrame, then we'll // include the regions where the tap is valid instead of just the button layout location if (useNearestRegion && mButtonFullTouchableRegions.containsKey(view)) { mTmpRegion.op(mButtonFullTouchableRegions.get(view), Op.UNION); return; } updateButtonLocation(view, inScreenSpace); } private void updateButtonLocation(View view, boolean inScreenSpace) { if (inScreenSpace) { view.getBoundsOnScreen(mTmpBounds); } else { view.getLocationInWindow(mTmpPosition); mTmpBounds.set(mTmpPosition[0], mTmpPosition[1], mTmpPosition[0] + view.getWidth(), mTmpPosition[1] + view.getHeight()); } mTmpRegion.op(mTmpBounds, Op.UNION); } private void updateOrientationViews() { mHorizontal = findViewById(R.id.horizontal); mVertical = findViewById(R.id.vertical); Loading Loading @@ -1272,7 +1167,6 @@ public class NavigationBarView extends FrameLayout { mRotationButtonController.registerListeners(); } getViewTreeObserver().addOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener); updateNavButtonIcons(); } Loading @@ -1288,8 +1182,6 @@ public class NavigationBarView extends FrameLayout { } mEdgeBackGestureHandler.onNavBarDetached(); getViewTreeObserver().removeOnComputeInternalInsetsListener( mOnComputeInternalInsetsListener); } public void dump(PrintWriter pw) { Loading
packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java +4 −5 Original line number Diff line number Diff line Loading @@ -60,6 +60,7 @@ import android.view.Display; import android.view.DisplayInfo; import android.view.MotionEvent; import android.view.View; import android.view.ViewTreeObserver; import android.view.WindowInsets; import android.view.WindowManager; import android.view.WindowMetrics; Loading Loading @@ -164,7 +165,7 @@ public class NavigationBarTest extends SysuiTestCase { @Mock private UiEventLogger mUiEventLogger; @Mock EdgeBackGestureHandler.Factory mEdgeBackGestureHandlerFactory; private ViewTreeObserver mViewTreeObserver; @Mock EdgeBackGestureHandler mEdgeBackGestureHandler; NavBarHelper mNavBarHelper; Loading Loading @@ -199,8 +200,6 @@ public class NavigationBarTest extends SysuiTestCase { public void setup() throws Exception { MockitoAnnotations.initMocks(this); when(mEdgeBackGestureHandlerFactory.create(any(Context.class))) .thenReturn(mEdgeBackGestureHandler); when(mLightBarcontrollerFactory.create(any(Context.class))).thenReturn(mLightBarController); when(mAutoHideControllerFactory.create(any(Context.class))).thenReturn(mAutoHideController); when(mNavigationBarView.getHomeButton()).thenReturn(mHomeButton); Loading @@ -213,6 +212,7 @@ public class NavigationBarTest extends SysuiTestCase { when(mNavigationBarTransitions.getLightTransitionsController()) .thenReturn(mLightBarTransitionsController); when(mStatusBarKeyguardViewManager.isNavBarVisible()).thenReturn(true); when(mNavigationBarView.getViewTreeObserver()).thenReturn(mViewTreeObserver); when(mUserContextProvider.createCurrentUserContext(any(Context.class))) .thenReturn(mContext); setupSysuiDependency(); Loading @@ -222,8 +222,6 @@ public class NavigationBarTest extends SysuiTestCase { mDependency.injectMockDependency(KeyguardStateController.class); mDependency.injectTestDependency(StatusBarStateController.class, mStatusBarStateController); mDependency.injectMockDependency(NavigationBarController.class); mDependency.injectTestDependency(EdgeBackGestureHandler.Factory.class, mEdgeBackGestureHandlerFactory); mDependency.injectTestDependency(OverviewProxyService.class, mOverviewProxyService); mDependency.injectTestDependency(NavigationModeController.class, mNavigationModeController); TestableLooper.get(this).runWithLooper(() -> { Loading Loading @@ -463,6 +461,7 @@ public class NavigationBarTest extends SysuiTestCase { mDeadZone, mDeviceConfigProxyFake, mNavigationBarTransitions, mEdgeBackGestureHandler, Optional.of(mock(BackAnimation.class)), mUserContextProvider)); } Loading