Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 84d455cc authored by Caitlin Shkuratov's avatar Caitlin Shkuratov Committed by Android (Google) Code Review
Browse files

Merge "[SB][Chips] Allow swipe to open shade over status bar chip." into main

parents 501ed30e d85cb18b
Loading
Loading
Loading
Loading
+10 −0
Original line number Original line Diff line number Diff line
@@ -376,6 +376,16 @@ flag {
    bug: "354930838"
    bug: "354930838"
}
}


flag {
    name: "status_bar_swipe_over_chip"
    namespace: "systemui"
    description: "Allow users to swipe over the status bar chip to open the shade"
    bug: "185897191"
    metadata {
      purpose: PURPOSE_BUGFIX
    }
}

flag {
flag {
    name: "compose_bouncer"
    name: "compose_bouncer"
    namespace: "systemui"
    namespace: "systemui"
+7 −2
Original line number Original line Diff line number Diff line
@@ -36,6 +36,7 @@ import android.widget.LinearLayout;


import com.android.internal.policy.SystemBarUtils;
import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.Dependency;
import com.android.systemui.Dependency;
import com.android.systemui.Flags;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
@@ -217,9 +218,13 @@ public class PhoneStatusBarView extends FrameLayout {


    @Override
    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
    public boolean onInterceptTouchEvent(MotionEvent event) {
        if (Flags.statusBarSwipeOverChip()) {
            return mTouchEventHandler.onInterceptTouchEvent(event);
        } else {
            mTouchEventHandler.onInterceptTouchEvent(event);
            mTouchEventHandler.onInterceptTouchEvent(event);
            return super.onInterceptTouchEvent(event);
            return super.onInterceptTouchEvent(event);
        }
        }
    }


    public void updateResources() {
    public void updateResources() {
        mCutoutSideNudge = getResources().getDimensionPixelSize(
        mCutoutSideNudge = getResources().getDimensionPixelSize(
+25 −17
Original line number Original line Diff line number Diff line
@@ -23,9 +23,10 @@ import android.view.MotionEvent
import android.view.View
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.view.ViewTreeObserver
import com.android.systemui.Flags
import com.android.systemui.Gefingerpoken
import com.android.systemui.Gefingerpoken
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.flags.Flags.ENABLE_UNFOLD_STATUS_BAR_ANIMATIONS
import com.android.systemui.res.R
import com.android.systemui.res.R
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.ui.view.WindowRootView
import com.android.systemui.scene.ui.view.WindowRootView
@@ -83,12 +84,14 @@ private constructor(
        statusContainer.setOnHoverListener(
        statusContainer.setOnHoverListener(
            statusOverlayHoverListenerFactory.createDarkAwareListener(statusContainer)
            statusOverlayHoverListenerFactory.createDarkAwareListener(statusContainer)
        )
        )
        statusContainer.setOnTouchListener(object : View.OnTouchListener {
        statusContainer.setOnTouchListener(
            object : View.OnTouchListener {
                override fun onTouch(v: View, event: MotionEvent): Boolean {
                override fun onTouch(v: View, event: MotionEvent): Boolean {
                // We want to handle only mouse events here to avoid stealing finger touches from
                    // We want to handle only mouse events here to avoid stealing finger touches
                // status bar which expands shade when swiped down on. We're using onTouchListener
                    // from status bar which expands shade when swiped down on. See b/326097469.
                // instead of onClickListener as the later will lead to isClickable being set to
                    // We're using onTouchListener instead of onClickListener as the later will lead
                // true and hence ALL touches always being intercepted. See [View.OnTouchEvent]
                    // to isClickable being set to true and hence ALL touches always being
                    // intercepted. See [View.OnTouchEvent]
                    if (event.source == InputDevice.SOURCE_MOUSE) {
                    if (event.source == InputDevice.SOURCE_MOUSE) {
                        if (event.action == MotionEvent.ACTION_UP) {
                        if (event.action == MotionEvent.ACTION_UP) {
                            v.performClick()
                            v.performClick()
@@ -98,7 +101,8 @@ private constructor(
                    }
                    }
                    return false
                    return false
                }
                }
        })
            }
        )


        progressProvider?.setReadyToHandleTransition(true)
        progressProvider?.setReadyToHandleTransition(true)
        configurationController.addCallback(configurationListener)
        configurationController.addCallback(configurationListener)
@@ -180,8 +184,12 @@ private constructor(


    inner class PhoneStatusBarViewTouchHandler : Gefingerpoken {
    inner class PhoneStatusBarViewTouchHandler : Gefingerpoken {
        override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
        override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
            return if (Flags.statusBarSwipeOverChip()) {
                shadeViewController.handleExternalInterceptTouch(event)
            } else {
                onTouch(event)
                onTouch(event)
            return false
                false
            }
        }
        }


        override fun onTouchEvent(event: MotionEvent): Boolean {
        override fun onTouchEvent(event: MotionEvent): Boolean {
@@ -280,7 +288,7 @@ private constructor(
    ) {
    ) {
        fun create(view: PhoneStatusBarView): PhoneStatusBarViewController {
        fun create(view: PhoneStatusBarView): PhoneStatusBarViewController {
            val statusBarMoveFromCenterAnimationController =
            val statusBarMoveFromCenterAnimationController =
                if (featureFlags.isEnabled(Flags.ENABLE_UNFOLD_STATUS_BAR_ANIMATIONS)) {
                if (featureFlags.isEnabled(ENABLE_UNFOLD_STATUS_BAR_ANIMATIONS)) {
                    unfoldComponent.getOrNull()?.getStatusBarMoveFromCenterAnimationController()
                    unfoldComponent.getOrNull()?.getStatusBarMoveFromCenterAnimationController()
                } else {
                } else {
                    null
                    null
+72 −27
Original line number Original line Diff line number Diff line
@@ -20,6 +20,8 @@ import android.app.StatusBarManager.WINDOW_STATE_HIDDEN
import android.app.StatusBarManager.WINDOW_STATE_HIDING
import android.app.StatusBarManager.WINDOW_STATE_HIDING
import android.app.StatusBarManager.WINDOW_STATE_SHOWING
import android.app.StatusBarManager.WINDOW_STATE_SHOWING
import android.app.StatusBarManager.WINDOW_STATUS_BAR
import android.app.StatusBarManager.WINDOW_STATUS_BAR
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.view.InputDevice
import android.view.InputDevice
import android.view.LayoutInflater
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.MotionEvent
@@ -112,8 +114,8 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
    @Test
    @Test
    fun onViewAttachedAndDrawn_startListeningConfigurationControllerCallback() {
    fun onViewAttachedAndDrawn_startListeningConfigurationControllerCallback() {
        val view = createViewMock()
        val view = createViewMock()
        val argumentCaptor = ArgumentCaptor.forClass(
        val argumentCaptor =
                ConfigurationController.ConfigurationListener::class.java)
            ArgumentCaptor.forClass(ConfigurationController.ConfigurationListener::class.java)
        InstrumentationRegistry.getInstrumentation().runOnMainSync {
        InstrumentationRegistry.getInstrumentation().runOnMainSync {
            controller = createAndInitController(view)
            controller = createAndInitController(view)
        }
        }
@@ -159,7 +161,7 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
    fun handleTouchEventFromStatusBar_panelsNotEnabled_returnsFalseAndNoViewEvent() {
    fun handleTouchEventFromStatusBar_panelsNotEnabled_returnsFalseAndNoViewEvent() {
        `when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(false)
        `when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(false)
        val returnVal =
        val returnVal =
            view.onTouchEvent(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0))
            view.onTouchEvent(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 2f, 0))
        assertThat(returnVal).isFalse()
        assertThat(returnVal).isFalse()
        verify(shadeViewController, never()).handleExternalTouch(any())
        verify(shadeViewController, never()).handleExternalTouch(any())
    }
    }
@@ -169,7 +171,7 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
        `when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
        `when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
        `when`(shadeViewController.isViewEnabled).thenReturn(false)
        `when`(shadeViewController.isViewEnabled).thenReturn(false)
        val returnVal =
        val returnVal =
            view.onTouchEvent(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0))
            view.onTouchEvent(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 2f, 0))
        assertThat(returnVal).isTrue()
        assertThat(returnVal).isTrue()
        verify(shadeViewController, never()).handleExternalTouch(any())
        verify(shadeViewController, never()).handleExternalTouch(any())
    }
    }
@@ -178,7 +180,7 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
    fun handleTouchEventFromStatusBar_viewNotEnabledButIsMoveEvent_viewReceivesEvent() {
    fun handleTouchEventFromStatusBar_viewNotEnabledButIsMoveEvent_viewReceivesEvent() {
        `when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
        `when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
        `when`(shadeViewController.isViewEnabled).thenReturn(false)
        `when`(shadeViewController.isViewEnabled).thenReturn(false)
        val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0)
        val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 2f, 0)


        view.onTouchEvent(event)
        view.onTouchEvent(event)


@@ -207,6 +209,50 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
        verify(shadeViewController, never()).handleExternalTouch(any())
        verify(shadeViewController, never()).handleExternalTouch(any())
    }
    }


    @Test
    @DisableFlags(com.android.systemui.Flags.FLAG_STATUS_BAR_SWIPE_OVER_CHIP)
    fun handleInterceptTouchEventFromStatusBar_shadeReturnsFalse_flagOff_viewReturnsFalse() {
        `when`(shadeViewController.handleExternalInterceptTouch(any())).thenReturn(false)
        val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 2f, 0)

        val returnVal = view.onInterceptTouchEvent(event)

        assertThat(returnVal).isFalse()
    }

    @Test
    @EnableFlags(com.android.systemui.Flags.FLAG_STATUS_BAR_SWIPE_OVER_CHIP)
    fun handleInterceptTouchEventFromStatusBar_shadeReturnsFalse_flagOn_viewReturnsFalse() {
        `when`(shadeViewController.handleExternalInterceptTouch(any())).thenReturn(false)
        val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 2f, 0)

        val returnVal = view.onInterceptTouchEvent(event)

        assertThat(returnVal).isFalse()
    }

    @Test
    @DisableFlags(com.android.systemui.Flags.FLAG_STATUS_BAR_SWIPE_OVER_CHIP)
    fun handleInterceptTouchEventFromStatusBar_shadeReturnsTrue_flagOff_viewReturnsFalse() {
        `when`(shadeViewController.handleExternalInterceptTouch(any())).thenReturn(true)
        val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 2f, 0)

        val returnVal = view.onInterceptTouchEvent(event)

        assertThat(returnVal).isFalse()
    }

    @Test
    @EnableFlags(com.android.systemui.Flags.FLAG_STATUS_BAR_SWIPE_OVER_CHIP)
    fun handleInterceptTouchEventFromStatusBar_shadeReturnsTrue_flagOn_viewReturnsTrue() {
        `when`(shadeViewController.handleExternalInterceptTouch(any())).thenReturn(true)
        val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 2f, 0)

        val returnVal = view.onInterceptTouchEvent(event)

        assertThat(returnVal).isTrue()
    }

    @Test
    @Test
    fun onTouch_windowHidden_centralSurfacesNotNotified() {
    fun onTouch_windowHidden_centralSurfacesNotNotified() {
        val callback = getCommandQueueCallback()
        val callback = getCommandQueueCallback()
@@ -244,9 +290,7 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
            controller = createAndInitController(view)
            controller = createAndInitController(view)
        }
        }
        val statusContainer = view.requireViewById<View>(R.id.system_icons)
        val statusContainer = view.requireViewById<View>(R.id.system_icons)
        statusContainer.dispatchTouchEvent(
        statusContainer.dispatchTouchEvent(getActionUpEventFromSource(InputDevice.SOURCE_MOUSE))
            getActionUpEventFromSource(InputDevice.SOURCE_MOUSE)
        )
        verify(shadeControllerImpl).animateExpandShade()
        verify(shadeControllerImpl).animateExpandShade()
    }
    }


@@ -257,7 +301,8 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
            controller = createAndInitController(view)
            controller = createAndInitController(view)
        }
        }
        val statusContainer = view.requireViewById<View>(R.id.system_icons)
        val statusContainer = view.requireViewById<View>(R.id.system_icons)
        val handled = statusContainer.dispatchTouchEvent(
        val handled =
            statusContainer.dispatchTouchEvent(
                getActionUpEventFromSource(InputDevice.SOURCE_TOUCHSCREEN)
                getActionUpEventFromSource(InputDevice.SOURCE_TOUCHSCREEN)
            )
            )
        assertThat(handled).isFalse()
        assertThat(handled).isFalse()
+65 −1
Original line number Original line Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.systemui.statusbar.phone
import android.content.res.Configuration
import android.content.res.Configuration
import android.graphics.Insets
import android.graphics.Insets
import android.graphics.Rect
import android.graphics.Rect
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.testing.TestableLooper.RunWithLooper
import android.testing.TestableLooper.RunWithLooper
import android.view.DisplayCutout
import android.view.DisplayCutout
import android.view.DisplayShape
import android.view.DisplayShape
@@ -30,6 +32,7 @@ import android.view.View
import android.view.WindowInsets
import android.view.WindowInsets
import android.widget.FrameLayout
import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import androidx.test.filters.SmallTest
import com.android.systemui.Flags.FLAG_STATUS_BAR_SWIPE_OVER_CHIP
import com.android.systemui.Gefingerpoken
import com.android.systemui.Gefingerpoken
import com.android.systemui.SysuiTestCase
import com.android.systemui.SysuiTestCase
import com.android.systemui.plugins.DarkIconDispatcher
import com.android.systemui.plugins.DarkIconDispatcher
@@ -82,7 +85,8 @@ class PhoneStatusBarViewTest : SysuiTestCase() {
    }
    }


    @Test
    @Test
    fun onInterceptTouchEvent_listenerNotified() {
    @DisableFlags(FLAG_STATUS_BAR_SWIPE_OVER_CHIP)
    fun onInterceptTouchEvent_flagOff_listenerNotified() {
        val handler = TestTouchEventHandler()
        val handler = TestTouchEventHandler()
        view.setTouchEventHandler(handler)
        view.setTouchEventHandler(handler)


@@ -92,6 +96,66 @@ class PhoneStatusBarViewTest : SysuiTestCase() {
        assertThat(handler.lastInterceptEvent).isEqualTo(event)
        assertThat(handler.lastInterceptEvent).isEqualTo(event)
    }
    }


    @Test
    @EnableFlags(FLAG_STATUS_BAR_SWIPE_OVER_CHIP)
    fun onInterceptTouchEvent_flagOn_listenerNotified() {
        val handler = TestTouchEventHandler()
        view.setTouchEventHandler(handler)

        val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
        view.onInterceptTouchEvent(event)

        assertThat(handler.lastInterceptEvent).isEqualTo(event)
    }

    @Test
    @DisableFlags(FLAG_STATUS_BAR_SWIPE_OVER_CHIP)
    fun onInterceptTouchEvent_listenerReturnsFalse_flagOff_viewReturnsFalse() {
        val handler = TestTouchEventHandler()
        view.setTouchEventHandler(handler)
        val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)

        handler.handleTouchReturnValue = false

        assertThat(view.onInterceptTouchEvent(event)).isFalse()
    }

    @Test
    @EnableFlags(FLAG_STATUS_BAR_SWIPE_OVER_CHIP)
    fun onInterceptTouchEvent_listenerReturnsFalse_flagOn_viewReturnsFalse() {
        val handler = TestTouchEventHandler()
        view.setTouchEventHandler(handler)
        val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)

        handler.handleTouchReturnValue = false

        assertThat(view.onInterceptTouchEvent(event)).isFalse()
    }

    @Test
    @DisableFlags(FLAG_STATUS_BAR_SWIPE_OVER_CHIP)
    fun onInterceptTouchEvent_listenerReturnsTrue_flagOff_viewReturnsFalse() {
        val handler = TestTouchEventHandler()
        view.setTouchEventHandler(handler)
        val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)

        handler.handleTouchReturnValue = true

        assertThat(view.onInterceptTouchEvent(event)).isFalse()
    }

    @Test
    @EnableFlags(FLAG_STATUS_BAR_SWIPE_OVER_CHIP)
    fun onInterceptTouchEvent_listenerReturnsTrue_flagOn_viewReturnsTrue() {
        val handler = TestTouchEventHandler()
        view.setTouchEventHandler(handler)
        val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)

        handler.handleTouchReturnValue = true

        assertThat(view.onInterceptTouchEvent(event)).isTrue()
    }

    @Test
    @Test
    fun onTouchEvent_listenerReturnsTrue_viewReturnsTrue() {
    fun onTouchEvent_listenerReturnsTrue_viewReturnsTrue() {
        val handler = TestTouchEventHandler()
        val handler = TestTouchEventHandler()