Merge "Fix split_shade_status_bar height to avoid layout on each animation frame" into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
7db06f8503
@@ -14,12 +14,17 @@
|
|||||||
~ See the License for the specific language governing permissions and
|
~ See the License for the specific language governing permissions and
|
||||||
~ limitations under the License.
|
~ limitations under the License.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
keep split_shade_status_bar height constant to avoid requestLayout calls on each
|
||||||
|
frame when animating QS <-> QQS transition
|
||||||
|
-->
|
||||||
<com.android.systemui.util.NoRemeasureMotionLayout
|
<com.android.systemui.util.NoRemeasureMotionLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:id="@+id/split_shade_status_bar"
|
android:id="@+id/split_shade_status_bar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="@dimen/qs_header_height"
|
||||||
android:minHeight="@dimen/large_screen_shade_header_min_height"
|
android:minHeight="@dimen/large_screen_shade_header_min_height"
|
||||||
android:clickable="false"
|
android:clickable="false"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
@@ -29,6 +34,14 @@
|
|||||||
android:theme="@style/Theme.SystemUI.QuickSettings.Header"
|
android:theme="@style/Theme.SystemUI.QuickSettings.Header"
|
||||||
app:layoutDescription="@xml/combined_qs_header_scene">
|
app:layoutDescription="@xml/combined_qs_header_scene">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.Guideline
|
||||||
|
android:id="@+id/qqs_header_bottom_guideline"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintGuide_begin="@dimen/large_screen_shade_header_min_height"
|
||||||
|
/>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.Guideline
|
<androidx.constraintlayout.widget.Guideline
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|||||||
@@ -615,6 +615,7 @@
|
|||||||
<dimen name="qs_header_carrier_separator_width">6dp</dimen>
|
<dimen name="qs_header_carrier_separator_width">6dp</dimen>
|
||||||
<dimen name="qs_carrier_margin_width">4dp</dimen>
|
<dimen name="qs_carrier_margin_width">4dp</dimen>
|
||||||
<dimen name="qs_footer_icon_size">20dp</dimen>
|
<dimen name="qs_footer_icon_size">20dp</dimen>
|
||||||
|
<dimen name="qs_header_height">120dp</dimen>
|
||||||
<dimen name="qs_header_row_min_height">48dp</dimen>
|
<dimen name="qs_header_row_min_height">48dp</dimen>
|
||||||
|
|
||||||
<dimen name="qs_header_non_clickable_element_height">24dp</dimen>
|
<dimen name="qs_header_non_clickable_element_height">24dp</dimen>
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
android:layout_height="@dimen/large_screen_shade_header_min_height"
|
android:layout_height="@dimen/large_screen_shade_header_min_height"
|
||||||
app:layout_constraintStart_toStartOf="@id/begin_guide"
|
app:layout_constraintStart_toStartOf="@id/begin_guide"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="@id/qqs_header_bottom_guideline"
|
||||||
app:layout_constraintEnd_toStartOf="@id/date"
|
app:layout_constraintEnd_toStartOf="@id/date"
|
||||||
app:layout_constraintHorizontal_bias="0"
|
app:layout_constraintHorizontal_bias="0"
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
@@ -62,7 +62,7 @@
|
|||||||
app:layout_constraintStart_toEndOf="@id/date"
|
app:layout_constraintStart_toEndOf="@id/date"
|
||||||
app:layout_constraintEnd_toStartOf="@id/batteryRemainingIcon"
|
app:layout_constraintEnd_toStartOf="@id/batteryRemainingIcon"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="@id/qqs_header_bottom_guideline"
|
||||||
app:layout_constraintHorizontal_bias="1"
|
app:layout_constraintHorizontal_bias="1"
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
/>
|
/>
|
||||||
@@ -77,7 +77,7 @@
|
|||||||
app:layout_constraintStart_toEndOf="@id/statusIcons"
|
app:layout_constraintStart_toEndOf="@id/statusIcons"
|
||||||
app:layout_constraintEnd_toEndOf="@id/end_guide"
|
app:layout_constraintEnd_toEndOf="@id/end_guide"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="@id/qqs_header_bottom_guideline"
|
||||||
app:layout_constraintHorizontal_bias="1"
|
app:layout_constraintHorizontal_bias="1"
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
/>
|
/>
|
||||||
@@ -105,7 +105,7 @@
|
|||||||
app:layout_constraintStart_toEndOf="@id/date"
|
app:layout_constraintStart_toEndOf="@id/date"
|
||||||
app:layout_constraintEnd_toEndOf="@id/end_guide"
|
app:layout_constraintEnd_toEndOf="@id/end_guide"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="@id/qqs_header_bottom_guideline"
|
||||||
app:layout_constraintHorizontal_bias="1"
|
app:layout_constraintHorizontal_bias="1"
|
||||||
/>
|
/>
|
||||||
</Constraint>
|
</Constraint>
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ package com.android.systemui.shade
|
|||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
|
||||||
import android.view.WindowInsets
|
import android.view.WindowInsets
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
import androidx.constraintlayout.widget.ConstraintSet
|
import androidx.constraintlayout.widget.ConstraintSet
|
||||||
@@ -62,6 +61,7 @@ class NotificationsQSContainerController @Inject constructor(
|
|||||||
private var isQSCustomizing = false
|
private var isQSCustomizing = false
|
||||||
private var isQSCustomizerAnimating = false
|
private var isQSCustomizerAnimating = false
|
||||||
|
|
||||||
|
private var shadeHeaderHeight = 0
|
||||||
private var largeScreenShadeHeaderHeight = 0
|
private var largeScreenShadeHeaderHeight = 0
|
||||||
private var largeScreenShadeHeaderActive = false
|
private var largeScreenShadeHeaderActive = false
|
||||||
private var notificationsBottomMargin = 0
|
private var notificationsBottomMargin = 0
|
||||||
@@ -146,6 +146,8 @@ class NotificationsQSContainerController @Inject constructor(
|
|||||||
R.dimen.notification_panel_margin_bottom)
|
R.dimen.notification_panel_margin_bottom)
|
||||||
largeScreenShadeHeaderHeight =
|
largeScreenShadeHeaderHeight =
|
||||||
resources.getDimensionPixelSize(R.dimen.large_screen_shade_header_height)
|
resources.getDimensionPixelSize(R.dimen.large_screen_shade_header_height)
|
||||||
|
shadeHeaderHeight =
|
||||||
|
resources.getDimensionPixelSize(R.dimen.qs_header_height)
|
||||||
panelMarginHorizontal = resources.getDimensionPixelSize(
|
panelMarginHorizontal = resources.getDimensionPixelSize(
|
||||||
R.dimen.notification_panel_margin_horizontal)
|
R.dimen.notification_panel_margin_horizontal)
|
||||||
topMargin = if (largeScreenShadeHeaderActive) {
|
topMargin = if (largeScreenShadeHeaderActive) {
|
||||||
@@ -245,7 +247,7 @@ class NotificationsQSContainerController @Inject constructor(
|
|||||||
if (largeScreenShadeHeaderActive) {
|
if (largeScreenShadeHeaderActive) {
|
||||||
constraintSet.constrainHeight(R.id.split_shade_status_bar, largeScreenShadeHeaderHeight)
|
constraintSet.constrainHeight(R.id.split_shade_status_bar, largeScreenShadeHeaderHeight)
|
||||||
} else {
|
} else {
|
||||||
constraintSet.constrainHeight(R.id.split_shade_status_bar, WRAP_CONTENT)
|
constraintSet.constrainHeight(R.id.split_shade_status_bar, shadeHeaderHeight)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.shade
|
||||||
|
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import android.testing.TestableLooper
|
||||||
|
import android.testing.TestableResources
|
||||||
|
import androidx.constraintlayout.widget.ConstraintSet
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.R
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.fragments.FragmentService
|
||||||
|
import com.android.systemui.navigationbar.NavigationModeController
|
||||||
|
import com.android.systemui.recents.OverviewProxyService
|
||||||
|
import com.android.systemui.util.concurrency.DelayableExecutor
|
||||||
|
import com.android.systemui.util.concurrency.FakeExecutor
|
||||||
|
import com.android.systemui.util.mockito.capture
|
||||||
|
import com.android.systemui.util.mockito.whenever
|
||||||
|
import com.android.systemui.util.time.FakeSystemClock
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.ArgumentCaptor
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
@TestableLooper.RunWithLooper
|
||||||
|
@SmallTest
|
||||||
|
class NotificationsQSContainerControllerTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
@Mock lateinit var view: NotificationsQuickSettingsContainer
|
||||||
|
@Mock lateinit var navigationModeController: NavigationModeController
|
||||||
|
@Mock lateinit var overviewProxyService: OverviewProxyService
|
||||||
|
@Mock lateinit var shadeHeaderController: ShadeHeaderController
|
||||||
|
@Mock lateinit var shadeExpansionStateManager: ShadeExpansionStateManager
|
||||||
|
@Mock lateinit var fragmentService: FragmentService
|
||||||
|
|
||||||
|
lateinit var underTest: NotificationsQSContainerController
|
||||||
|
|
||||||
|
private lateinit var fakeResources: TestableResources
|
||||||
|
|
||||||
|
private val delayableExecutor: DelayableExecutor = FakeExecutor(FakeSystemClock())
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
fakeResources = TestableResources(context.resources)
|
||||||
|
|
||||||
|
whenever(view.resources).thenReturn(fakeResources.resources)
|
||||||
|
|
||||||
|
underTest =
|
||||||
|
NotificationsQSContainerController(
|
||||||
|
view,
|
||||||
|
navigationModeController,
|
||||||
|
overviewProxyService,
|
||||||
|
shadeHeaderController,
|
||||||
|
shadeExpansionStateManager,
|
||||||
|
fragmentService,
|
||||||
|
delayableExecutor,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSmallScreen_updateResources_splitShadeHeightIsSet() {
|
||||||
|
with(fakeResources) {
|
||||||
|
addOverride(R.bool.config_use_large_screen_shade_header, false)
|
||||||
|
addOverride(R.dimen.qs_header_height, 1)
|
||||||
|
addOverride(R.dimen.large_screen_shade_header_height, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
underTest.updateResources()
|
||||||
|
|
||||||
|
val captor = ArgumentCaptor.forClass(ConstraintSet::class.java)
|
||||||
|
verify(view).applyConstraints(capture(captor))
|
||||||
|
assertThat(captor.value.getHeight(R.id.split_shade_status_bar)).isEqualTo(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testLargeScreen_updateResources_splitShadeHeightIsSet() {
|
||||||
|
with(fakeResources) {
|
||||||
|
addOverride(R.bool.config_use_large_screen_shade_header, true)
|
||||||
|
addOverride(R.dimen.qs_header_height, 1)
|
||||||
|
addOverride(R.dimen.large_screen_shade_header_height, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
underTest.updateResources()
|
||||||
|
|
||||||
|
val captor = ArgumentCaptor.forClass(ConstraintSet::class.java)
|
||||||
|
verify(view).applyConstraints(capture(captor))
|
||||||
|
assertThat(captor.value.getHeight(R.id.split_shade_status_bar)).isEqualTo(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user