Merge "Disabled SUBPIXEL_TEXT_FLAG for notification shade while fold unfold" into udc-dev

This commit is contained in:
Shivangi Dubey
2023-05-03 17:13:23 +00:00
committed by Android (Google) Code Review
7 changed files with 242 additions and 1 deletions

View File

@@ -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))
}
}
}
}
}
}

View File

@@ -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")

View File

@@ -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();

View File

@@ -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,

View File

@@ -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,

View File

@@ -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)
}
}