Loading packages/SystemUI/shared/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListener.kt 0 → 100644 +84 −0 Original line number Diff line number Diff line /* * 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)) } } } } } } packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt→packages/SystemUI/shared/src/com/android/systemui/utils/TraceUtils.kt +0 −0 File moved. View file packages/SystemUI/src/com/android/systemui/flags/Flags.kt +5 −0 Original line number Diff line number Diff line Loading @@ -700,6 +700,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 = releasedFlag(2801, name = "use_new_activity_starter") Loading packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +11 −1 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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 = Loading @@ -139,6 +142,7 @@ public class NotificationShadeWindowViewController { LockIconViewController lockIconViewController, CentralSurfaces centralSurfaces, NotificationShadeWindowController controller, Optional<UnfoldTransitionProgressProvider> unfoldTransitionProgressProvider, KeyguardUnlockAnimationController keyguardUnlockAnimationController, NotificationInsetsController notificationInsetsController, AmbientState ambientState, Loading Loading @@ -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, Loading @@ -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(); Loading packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt +6 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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() Loading Loading @@ -158,6 +163,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { lockIconViewController, centralSurfaces, notificationShadeWindowController, unfoldTransitionProgressProvider, keyguardUnlockAnimationController, notificationInsetsController, ambientState, Loading Loading
packages/SystemUI/shared/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListener.kt 0 → 100644 +84 −0 Original line number Diff line number Diff line /* * 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)) } } } } } }
packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt→packages/SystemUI/shared/src/com/android/systemui/utils/TraceUtils.kt +0 −0 File moved. View file
packages/SystemUI/src/com/android/systemui/flags/Flags.kt +5 −0 Original line number Diff line number Diff line Loading @@ -700,6 +700,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 = releasedFlag(2801, name = "use_new_activity_starter") Loading
packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +11 −1 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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 = Loading @@ -139,6 +142,7 @@ public class NotificationShadeWindowViewController { LockIconViewController lockIconViewController, CentralSurfaces centralSurfaces, NotificationShadeWindowController controller, Optional<UnfoldTransitionProgressProvider> unfoldTransitionProgressProvider, KeyguardUnlockAnimationController keyguardUnlockAnimationController, NotificationInsetsController notificationInsetsController, AmbientState ambientState, Loading Loading @@ -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, Loading @@ -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(); Loading
packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt +6 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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() Loading Loading @@ -158,6 +163,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { lockIconViewController, centralSurfaces, notificationShadeWindowController, unfoldTransitionProgressProvider, keyguardUnlockAnimationController, notificationInsetsController, ambientState, Loading