summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListener.kt84
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/utils/TraceUtils.kt (renamed from packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt)0
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListenerTest.kt130
7 files changed, 242 insertions, 1 deletions
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListener.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListener.kt
new file mode 100644
index 000000000000..4c6d99a412b7
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListener.kt
@@ -0,0 +1,84 @@
+/*
+ * 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.shared.animation
+
+import android.graphics.Paint
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.core.view.forEach
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.systemui.util.traceSection
+import java.lang.ref.WeakReference
+
+/**
+ * A listener which disables subpixel flag for all TextView children of a given parent ViewGroup
+ * during fold/unfold transitions.
+ */
+class DisableSubpixelTextTransitionListener(private val rootView: ViewGroup?) :
+ TransitionProgressListener {
+ private val childrenTextViews: MutableList<WeakReference<TextView>> = mutableListOf()
+ private var isTransitionInProgress: Boolean = false
+
+ override fun onTransitionStarted() {
+ isTransitionInProgress = true
+ traceSection("subpixelFlagSetForTextView") {
+ traceSection("subpixelFlagTraverseHierarchy") {
+ getAllChildTextView(rootView, childrenTextViews)
+ }
+ traceSection("subpixelFlagDisableForTextView") {
+ childrenTextViews.forEach { child ->
+ val childTextView = child.get() ?: return@forEach
+ childTextView.paintFlags = childTextView.paintFlags or Paint.SUBPIXEL_TEXT_FLAG
+ }
+ }
+ }
+ }
+
+ override fun onTransitionFinished() {
+ if (!isTransitionInProgress) return
+ isTransitionInProgress = false
+ traceSection("subpixelFlagEnableForTextView") {
+ childrenTextViews.forEach { child ->
+ val childTextView = child.get() ?: return@forEach
+ childTextView.paintFlags =
+ childTextView.paintFlags and Paint.SUBPIXEL_TEXT_FLAG.inv()
+ }
+ childrenTextViews.clear()
+ }
+ }
+
+ /**
+ * Populates a list of all TextView children of a given parent ViewGroup
+ *
+ * @param parent the root ViewGroup for which to retrieve TextView children
+ * @param childrenTextViews the list to store the retrieved TextView children
+ */
+ private fun getAllChildTextView(
+ parent: ViewGroup?,
+ childrenTextViews: MutableList<WeakReference<TextView>>
+ ) {
+ parent?.forEach { child ->
+ when (child) {
+ is ViewGroup -> getAllChildTextView(child, childrenTextViews)
+ is TextView -> {
+ if ((child.paintFlags and Paint.SUBPIXEL_TEXT_FLAG) <= 0) {
+ childrenTextViews.add(WeakReference(child))
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt b/packages/SystemUI/shared/src/com/android/systemui/utils/TraceUtils.kt
index 64234c205617..64234c205617 100644
--- a/packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/utils/TraceUtils.kt
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index cd2bf13e37a2..af6567dad8a3 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -689,6 +689,11 @@ object Flags {
val ADVANCED_VPN_ENABLED = releasedFlag(2800, name = "AdvancedVpn__enable_feature",
namespace = "vpn")
+ // TODO(b/277201412): Tracking Bug
+ @JvmField
+ val SPLIT_SHADE_SUBPIXEL_OPTIMIZATION =
+ unreleasedFlag(2805, "split_shade_subpixel_optimization", teamfood = true)
+
// TODO(b/278761837): Tracking Bug
@JvmField
val USE_NEW_ACTIVITY_STARTER = unreleasedFlag(2801, name = "use_new_activity_starter",
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 7cc257ba0a97..cb3fa15655b2 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -54,6 +54,7 @@ import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransition
import com.android.systemui.multishade.domain.interactor.MultiShadeInteractor;
import com.android.systemui.multishade.domain.interactor.MultiShadeMotionEventInteractor;
import com.android.systemui.multishade.ui.view.MultiShadeView;
+import com.android.systemui.shared.animation.DisableSubpixelTextTransitionListener;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationInsetsController;
@@ -68,9 +69,11 @@ import com.android.systemui.statusbar.phone.PhoneStatusBarViewController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
import com.android.systemui.statusbar.window.StatusBarWindowStateController;
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
import com.android.systemui.util.time.SystemClock;
import java.io.PrintWriter;
+import java.util.Optional;
import java.util.function.Consumer;
import javax.inject.Inject;
@@ -114,7 +117,7 @@ public class NotificationShadeWindowViewController {
private boolean mIsTrackingBarGesture = false;
private boolean mIsOcclusionTransitionRunning = false;
-
+ private DisableSubpixelTextTransitionListener mDisableSubpixelTextTransitionListener;
private final Consumer<TransitionStep> mLockscreenToDreamingTransition =
(TransitionStep step) -> {
mIsOcclusionTransitionRunning =
@@ -139,6 +142,7 @@ public class NotificationShadeWindowViewController {
LockIconViewController lockIconViewController,
CentralSurfaces centralSurfaces,
NotificationShadeWindowController controller,
+ Optional<UnfoldTransitionProgressProvider> unfoldTransitionProgressProvider,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
NotificationInsetsController notificationInsetsController,
AmbientState ambientState,
@@ -174,6 +178,7 @@ public class NotificationShadeWindowViewController {
// This view is not part of the newly inflated expanded status bar.
mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container);
+ mDisableSubpixelTextTransitionListener = new DisableSubpixelTextTransitionListener(mView);
KeyguardBouncerViewBinder.bind(
mView.findViewById(R.id.keyguard_bouncer_container),
keyguardBouncerViewModel,
@@ -184,6 +189,11 @@ public class NotificationShadeWindowViewController {
mLockscreenToDreamingTransition);
mClock = clock;
+ if (featureFlags.isEnabled(Flags.SPLIT_SHADE_SUBPIXEL_OPTIMIZATION)) {
+ unfoldTransitionProgressProvider.ifPresent(
+ progressProvider -> progressProvider.addCallback(
+ mDisableSubpixelTextTransitionListener));
+ }
if (ComposeFacade.INSTANCE.isComposeAvailable()
&& featureFlags.isEnabled(Flags.DUAL_SHADE)) {
mMultiShadeMotionEventInteractor = multiShadeMotionEventInteractorProvider.get();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index bc8ab1faf9eb..16277de850d6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -53,6 +53,7 @@ import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.phone.PhoneStatusBarViewController
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.android.systemui.statusbar.window.StatusBarWindowStateController
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider
import com.android.systemui.util.mockito.any
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -71,6 +72,7 @@ import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
+import java.util.Optional
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@@ -101,6 +103,8 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
@Mock lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory
@Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent
@Mock lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController
+ @Mock
+ private lateinit var unfoldTransitionProgressProvider: Optional<UnfoldTransitionProgressProvider>
@Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
@Mock
lateinit var primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel
@@ -129,6 +133,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
featureFlags.set(Flags.TRACKPAD_GESTURE_COMMON, true)
featureFlags.set(Flags.TRACKPAD_GESTURE_FEATURES, false)
featureFlags.set(Flags.DUAL_SHADE, false)
+ featureFlags.set(Flags.SPLIT_SHADE_SUBPIXEL_OPTIMIZATION, true)
val inputProxy = MultiShadeInputProxy()
testScope = TestScope()
@@ -158,6 +163,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
lockIconViewController,
centralSurfaces,
notificationShadeWindowController,
+ unfoldTransitionProgressProvider,
keyguardUnlockAnimationController,
notificationInsetsController,
ambientState,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index 56385b2ec5da..16af208fd531 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -53,6 +53,7 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll
import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.android.systemui.statusbar.window.StatusBarWindowStateController
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
@@ -71,6 +72,7 @@ import org.mockito.Mock
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import java.util.Optional
@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidTestingRunner::class)
@@ -103,6 +105,8 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
@Mock private lateinit var keyguardBouncerComponent: KeyguardBouncerComponent
@Mock
private lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController
+ @Mock
+ private lateinit var unfoldTransitionProgressProvider: Optional<UnfoldTransitionProgressProvider>
@Mock private lateinit var notificationInsetsController: NotificationInsetsController
@Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
@Mock
@@ -141,6 +145,7 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
featureFlags.set(Flags.TRACKPAD_GESTURE_COMMON, true)
featureFlags.set(Flags.TRACKPAD_GESTURE_FEATURES, false)
featureFlags.set(Flags.DUAL_SHADE, false)
+ featureFlags.set(Flags.SPLIT_SHADE_SUBPIXEL_OPTIMIZATION, true)
val inputProxy = MultiShadeInputProxy()
testScope = TestScope()
val multiShadeInteractor =
@@ -169,6 +174,7 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
lockIconViewController,
centralSurfaces,
notificationShadeWindowController,
+ unfoldTransitionProgressProvider,
keyguardUnlockAnimationController,
notificationInsetsController,
ambientState,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListenerTest.kt
new file mode 100644
index 000000000000..fc230e362735
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListenerTest.kt
@@ -0,0 +1,130 @@
+/*
+ * 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.shared.animation
+
+import android.graphics.Paint
+import android.testing.AndroidTestingRunner
+import android.widget.FrameLayout
+import android.widget.TextView
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class DisableSubpixelTextTransitionListenerTest : SysuiTestCase() {
+
+ private lateinit var disableSubpixelTextTransitionListener:
+ DisableSubpixelTextTransitionListener
+ private var rootViewWithNoTextView = FrameLayout(context)
+ private var rootView = FrameLayout(context)
+ private var childView = FrameLayout(context)
+ private var childViewWithNoTextView = FrameLayout(context)
+ private var childTextView = TextView(context)
+ private var childOfChildTextView = TextView(context)
+
+ @Before
+ fun setup() {
+
+ childView.addView(childOfChildTextView)
+ rootView.addView(childTextView)
+ rootView.addView(childView)
+ }
+
+ @Test
+ fun onTransitionStarted_addsSubpixelFlagToChildTextView() {
+ disableSubpixelTextTransitionListener = DisableSubpixelTextTransitionListener(rootView)
+
+ disableSubpixelTextTransitionListener.onTransitionStarted()
+
+ assertThat(childTextView.paintFlags and Paint.SUBPIXEL_TEXT_FLAG).isGreaterThan(0)
+ }
+
+ @Test
+ fun onTransitionStarted_addsSupbixelFlagToChildOfChildTextView() {
+ disableSubpixelTextTransitionListener = DisableSubpixelTextTransitionListener(rootView)
+
+ disableSubpixelTextTransitionListener.onTransitionStarted()
+
+ assertThat(childOfChildTextView.paintFlags and Paint.SUBPIXEL_TEXT_FLAG).isGreaterThan(0)
+ }
+
+ @Test
+ fun onTransitionFinished_removeSupbixelFlagFromChildTextView() {
+ disableSubpixelTextTransitionListener = DisableSubpixelTextTransitionListener(rootView)
+
+ disableSubpixelTextTransitionListener.onTransitionStarted()
+ disableSubpixelTextTransitionListener.onTransitionFinished()
+
+ assertThat(childTextView.paintFlags and Paint.SUBPIXEL_TEXT_FLAG).isEqualTo(0)
+ }
+
+ @Test
+ fun onTransitionFinished_removeSupbixelFlagFromChildOfChildTextView() {
+ disableSubpixelTextTransitionListener = DisableSubpixelTextTransitionListener(rootView)
+
+ disableSubpixelTextTransitionListener.onTransitionStarted()
+ disableSubpixelTextTransitionListener.onTransitionFinished()
+
+ assertThat(childOfChildTextView.paintFlags and Paint.SUBPIXEL_TEXT_FLAG).isEqualTo(0)
+ }
+
+ @Test
+ fun whenRootViewIsNull_runWithoutExceptions() {
+ disableSubpixelTextTransitionListener = DisableSubpixelTextTransitionListener(null)
+
+ disableSubpixelTextTransitionListener.onTransitionStarted()
+ disableSubpixelTextTransitionListener.onTransitionFinished()
+ }
+
+ @Test
+ fun whenFlagAlreadyPresent_flagNotRemovedOnTransitionFinished() {
+ childTextView.paintFlags = childTextView.paintFlags or Paint.SUBPIXEL_TEXT_FLAG
+ disableSubpixelTextTransitionListener = DisableSubpixelTextTransitionListener(rootView)
+
+ disableSubpixelTextTransitionListener.onTransitionStarted()
+ disableSubpixelTextTransitionListener.onTransitionFinished()
+
+ assertThat(childTextView.paintFlags and Paint.SUBPIXEL_TEXT_FLAG).isGreaterThan(0)
+ }
+
+ @Test
+ fun whenFlagNotPresent_flagRemovedOnTransitionFinished() {
+ childTextView.paintFlags = childTextView.paintFlags or Paint.SUBPIXEL_TEXT_FLAG
+ disableSubpixelTextTransitionListener = DisableSubpixelTextTransitionListener(rootView)
+
+ disableSubpixelTextTransitionListener.onTransitionStarted()
+ disableSubpixelTextTransitionListener.onTransitionFinished()
+
+ assertThat(childOfChildTextView.paintFlags and Paint.SUBPIXEL_TEXT_FLAG).isEqualTo(0)
+ }
+
+ @Test
+ fun whenRootViewHasNoChildTextView_flagNotAddedToRelatedTextviews() {
+ rootViewWithNoTextView.addView(childViewWithNoTextView)
+ rootView.addView(rootViewWithNoTextView)
+ disableSubpixelTextTransitionListener =
+ DisableSubpixelTextTransitionListener(rootViewWithNoTextView)
+
+ disableSubpixelTextTransitionListener.onTransitionStarted()
+
+ assertThat(childTextView.paintFlags and Paint.SUBPIXEL_TEXT_FLAG).isEqualTo(0)
+ }
+}